.htm]\n");
43 | return;
44 | }
45 |
46 | // auto-name output file
47 | if (args.length == 2)
48 | args ~= args[1] ~ ".htm";
49 |
50 | // load keywords
51 | assert("d2html.kwd".exists, "file d2html.kwd does not exist");
52 | auto kwd = File("d2html.kwd");
53 | foreach (word; kwd.byLine())
54 | keywords[word.idup] = true;
55 | kwd.close();
56 |
57 | // open input and output files
58 | auto src = File(args[1]);
59 | auto dst = File(args[2], "w");
60 |
61 | // write HTML header
62 | dst.writeln("" ~ args[1] ~ "");
63 | dst.writeln("");
64 |
65 | // the main part is wrapped into try..catch block because
66 | // when end of file is reached, an exception is raised;
67 | // so we can omit any checks for EOF inside this block...
68 | try
69 | {
70 | static char readc(ref File src)
71 | {
72 | while (true)
73 | {
74 | if (src.eof())
75 | throw new Exception("");
76 | char c;
77 | src.readf("%c", &c);
78 | if (c != '\r' && c != 0xFF)
79 | return c;
80 | }
81 | }
82 |
83 | ulong linestart = 0; // for tabs
84 | char c;
85 |
86 | c = readc(src);
87 |
88 | while (true)
89 | {
90 | if (isWhite(c)) // whitespace
91 | {
92 | do
93 | {
94 | if (c == 9)
95 | {
96 | // expand tabs to spaces
97 | immutable spaces = tabsize -
98 | (src.tell() - linestart) % tabsize;
99 |
100 | for (int i = 0; i < spaces; i++)
101 | dst.write(" ");
102 |
103 | linestart = src.tell() - tabsize + 1;
104 | }
105 | else
106 | {
107 | // reset line start on newline
108 | if (c == 10 || c == 13)
109 | linestart = src.tell() + 1;
110 |
111 | dst.write(c);
112 | }
113 |
114 | c = readc(src);
115 | } while (isWhite(c));
116 | }
117 | else if (isAlpha(c)) // keyword or identifier
118 | {
119 | string token;
120 |
121 | do
122 | {
123 | token ~= c;
124 | c = readc(src);
125 | } while (isAlpha(c) || isDigit(c));
126 |
127 | if (token in keywords) // keyword
128 | dst.write("" ~ token ~ "");
130 | else // simple identifier
131 | dst.write(token);
132 | }
133 | else if (c == '0') // binary, octal or hexadecimal number
134 | {
135 | dst.write("");
136 | dst.write(c);
137 | c = readc(src);
138 |
139 | if (c == 'X' || c == 'x') // hexadecimal
140 | {
141 | dst.write(c);
142 | c = readc(src);
143 |
144 | while (isHexDigit(c)) {
145 | dst.write(c);
146 | c = readc(src);
147 | }
148 |
149 | // TODO: add support for hexadecimal floats
150 | }
151 | else if (c == 'B' || c == 'b') // binary
152 | {
153 | dst.write(c);
154 | c = readc(src);
155 |
156 | while (c == '0' || c == '1') {
157 | dst.write(c);
158 | c = readc(src);
159 | }
160 | }
161 | else // octal
162 | {
163 | do
164 | {
165 | dst.write(c);
166 | c = readc(src);
167 | } while (isOctalDigit(c));
168 | }
169 |
170 | dst.write("");
171 | }
172 | else if (c == '#') // hash
173 | {
174 | dst.write(c);
175 | c = readc(src);
176 | }
177 | else if (c == '\\') // backward slash
178 | {
179 | dst.write(c);
180 | c = readc(src);
181 | }
182 | else if (isDigit(c)) // decimal number
183 | {
184 | dst.write("");
185 |
186 | // integral part
187 | do
188 | {
189 | dst.write(c);
190 | c = readc(src);
191 | } while (isDigit(c));
192 |
193 | // fractional part
194 | if (c == '.')
195 | {
196 | dst.write(c);
197 | c = readc(src);
198 |
199 | while (isDigit(c))
200 | {
201 | dst.write(c);
202 | c = readc(src);
203 | }
204 | }
205 |
206 | // scientific notation
207 | if (c == 'E' || c == 'e')
208 | {
209 | dst.write(c);
210 | c = readc(src);
211 |
212 | if (c == '+' || c == '-')
213 | {
214 | dst.write(c);
215 | c = readc(src);
216 | }
217 |
218 | while (isDigit(c))
219 | {
220 | dst.write(c);
221 | c = readc(src);
222 | }
223 | }
224 |
225 | // suffices
226 | while (c == 'U' || c == 'u' || c == 'L' ||
227 | c == 'l' || c == 'F' || c == 'f')
228 | {
229 | dst.write(c);
230 | c = readc(src);
231 | }
232 |
233 | dst.write("");
234 | }
235 | else if (c == '\'') // string without escape sequences
236 | {
237 | dst.write("");
238 |
239 | do
240 | {
241 | if (c == '<') // special symbol in HTML
242 | dst.write("<");
243 | else
244 | dst.write(c);
245 |
246 | c = readc(src);
247 | } while (c != '\'');
248 | dst.write(c);
249 | c = readc(src);
250 | dst.write("");
251 | }
252 | else if (c == 34) // string with escape sequences
253 | {
254 | dst.write("");
255 | char prev; // used to handle \" properly
256 |
257 | do
258 | {
259 | if (c == '<') // special symbol in HTML
260 | dst.write("<");
261 | else
262 | dst.write(c);
263 |
264 | prev = c;
265 | c = readc(src);
266 | } while (!(c == 34 && prev != '\\')); // handle \"
267 | dst.write(c);
268 | c = readc(src);
269 | dst.write("");
270 | }
271 | else if (isPunctuation(c)) // either operator or comment
272 | {
273 | if (c == '<') // special symbol in HTML
274 | {
275 | dst.write("<");
276 | c = readc(src);
277 | }
278 | else if (c == '/') // could be a comment...
279 | {
280 | c = readc(src);
281 |
282 | if (c == '/') // single-line one
283 | {
284 | dst.write("/");
285 |
286 | while (c != 10)
287 | {
288 | if (c == '<') // special symbol in HTML
289 | dst.write("<");
290 | else if (c == 9)
291 | {
292 | // expand tabs
293 | immutable spaces2 = tabsize -
294 | (src.tell() - linestart) % tabsize;
295 |
296 | for (int i2 = 0; i2 < spaces2; i2++)
297 | dst.write(" ");
298 |
299 | linestart = src.tell() - tabsize + 1;
300 | }
301 | else
302 | dst.write(c);
303 |
304 | c = readc(src);
305 | }
306 |
307 | dst.write("");
308 | }
309 | else if (c == '*') // multi-line one
310 | {
311 | dst.write("/");
312 | char prev2;
313 |
314 | do
315 | {
316 | if (c == '<') // special symbol in HTML
317 | dst.write("<");
318 | else if (c == 9)
319 | {
320 | // expand tabs
321 | immutable spaces3 = tabsize -
322 | (src.tell() - linestart) % tabsize;
323 |
324 | for (int i3 = 0; i3 < spaces3; i3++)
325 | dst.write(" ");
326 |
327 | linestart = src.tell() - tabsize + 1;
328 | }
329 | else
330 | {
331 | // reset line start on newline
332 | if (c == 10 || c == 13)
333 | linestart = src.tell() + 1;
334 |
335 | dst.write(c);
336 | }
337 |
338 | prev2 = c;
339 | c = readc(src);
340 | } while (!(c == '/' && prev2 == '*'));
341 | dst.write(c);
342 | dst.write("");
343 | c = readc(src);
344 | }
345 | else // just an operator
346 | dst.write(cast(char) '/');
347 | }
348 | else // just an operator
349 | {
350 | dst.write(c);
351 | c = readc(src);
352 | }
353 | }
354 | else
355 | {
356 | // whatever it is, it's not a valid D token
357 | throw new Error("unrecognized token " ~ c);
358 | //~ break;
359 | }
360 | }
361 | }
362 |
363 | // if end of file is reached and we try to read something
364 | // with typed read(), a ReadError is thrown; in our case,
365 | // this means that job is successfully done
366 | catch (Exception e)
367 | {
368 | // write HTML footer
369 | dst.writeln("
");
370 | }
371 |
372 | return;
373 | }
374 |
--------------------------------------------------------------------------------
/src/undead/bitarray.d:
--------------------------------------------------------------------------------
1 | /***********************
2 | * Source: $(PHOBOSSRC std/_bitarray.d)
3 | * Macros:
4 | * WIKI = StdBitarray
5 | */
6 |
7 | module undead.bitarray;
8 |
9 | //debug = bitarray; // uncomment to turn on debugging printf's
10 |
11 | private import core.bitop;
12 |
13 | /**
14 | * An array of bits.
15 | */
16 |
17 | struct BitArray
18 | {
19 | size_t len;
20 | size_t* ptr;
21 |
22 | size_t dim()
23 | {
24 | return (len + 31) / 32;
25 | }
26 |
27 | size_t length() const pure nothrow
28 | {
29 | return len;
30 | }
31 |
32 | void length(size_t newlen)
33 | {
34 | if (newlen != len)
35 | {
36 | size_t olddim = dim();
37 | size_t newdim = (newlen + 31) / 32;
38 |
39 | if (newdim != olddim)
40 | {
41 | // Create a fake array so we can use D's realloc machinery
42 | auto b = ptr[0 .. olddim];
43 | b.length = newdim; // realloc
44 | ptr = b.ptr;
45 | if (newdim & 31)
46 | { // Set any pad bits to 0
47 | ptr[newdim - 1] &= ~(~0 << (newdim & 31));
48 | }
49 | }
50 |
51 | len = newlen;
52 | }
53 | }
54 |
55 | /**********************************************
56 | * Support for [$(I index)] operation for BitArray.
57 | */
58 | bool opIndex(size_t i)
59 | in
60 | {
61 | assert(i < len);
62 | }
63 | do
64 | {
65 | return cast(bool)bt(ptr, i);
66 | }
67 |
68 | /** ditto */
69 | bool opIndexAssign(bool b, size_t i)
70 | in
71 | {
72 | assert(i < len);
73 | }
74 | do
75 | {
76 | if (b)
77 | bts(ptr, i);
78 | else
79 | btr(ptr, i);
80 | return b;
81 | }
82 |
83 | /**********************************************
84 | * Support for array.dup property for BitArray.
85 | */
86 | BitArray dup()
87 | {
88 | BitArray ba;
89 |
90 | auto b = ptr[0 .. dim].dup;
91 | ba.len = len;
92 | ba.ptr = b.ptr;
93 | return ba;
94 | }
95 |
96 | unittest
97 | {
98 | BitArray a;
99 | BitArray b;
100 |
101 | debug(bitarray) printf("BitArray.dup.unittest\n");
102 |
103 | a.length = 3;
104 | a[0] = 1; a[1] = 0; a[2] = 1;
105 | b = a.dup;
106 | assert(b.length == 3);
107 | for (int i = 0; i < 3; i++)
108 | { debug(bitarray) printf("b[%d] = %d\n", i, b[i]);
109 | assert(b[i] == (((i ^ 1) & 1) ? true : false));
110 | }
111 | }
112 |
113 | /**********************************************
114 | * Support for foreach loops for BitArray.
115 | */
116 | int opApply(int delegate(ref bool) dg)
117 | {
118 | int result;
119 |
120 | for (size_t i = 0; i < len; i++)
121 | { bool b = opIndex(i);
122 | result = dg(b);
123 | (this)[i] = b;
124 | if (result)
125 | break;
126 | }
127 | return result;
128 | }
129 |
130 | /** ditto */
131 | int opApply(int delegate(ref size_t, ref bool) dg)
132 | {
133 | int result;
134 |
135 | for (size_t i = 0; i < len; i++)
136 | { bool b = opIndex(i);
137 | result = dg(i, b);
138 | (this)[i] = b;
139 | if (result)
140 | break;
141 | }
142 | return result;
143 | }
144 |
145 | unittest
146 | {
147 | debug(bitarray) printf("BitArray.opApply unittest\n");
148 |
149 | static bool[] ba = [1,0,1];
150 |
151 | BitArray a; a.init(ba);
152 |
153 | int i;
154 | foreach (b;a)
155 | {
156 | switch (i)
157 | { case 0: assert(b == true); break;
158 | case 1: assert(b == false); break;
159 | case 2: assert(b == true); break;
160 | default: assert(0);
161 | }
162 | i++;
163 | }
164 |
165 | foreach (j,b;a)
166 | {
167 | switch (j)
168 | { case 0: assert(b == true); break;
169 | case 1: assert(b == false); break;
170 | case 2: assert(b == true); break;
171 | default: assert(0);
172 | }
173 | }
174 | }
175 |
176 |
177 | /**********************************************
178 | * Support for array.reverse property for BitArray.
179 | */
180 |
181 | BitArray reverse()
182 | out (result)
183 | {
184 | assert(result == this);
185 | }
186 | do
187 | {
188 | if (len >= 2)
189 | {
190 | bool t;
191 | size_t lo, hi;
192 |
193 | lo = 0;
194 | hi = len - 1;
195 | for (; lo < hi; lo++, hi--)
196 | {
197 | t = (this)[lo];
198 | (this)[lo] = (this)[hi];
199 | (this)[hi] = t;
200 | }
201 | }
202 | return this;
203 | }
204 |
205 | unittest
206 | {
207 | debug(bitarray) printf("BitArray.reverse.unittest\n");
208 |
209 | BitArray b;
210 | static bool[5] data = [1,0,1,1,0];
211 | int i;
212 |
213 | b.init(data);
214 | b.reverse;
215 | for (i = 0; i < data.length; i++)
216 | {
217 | assert(b[i] == data[4 - i]);
218 | }
219 | }
220 |
221 |
222 | /**********************************************
223 | * Support for array.sort property for BitArray.
224 | */
225 |
226 | BitArray sort()
227 | out (result)
228 | {
229 | assert(result == this);
230 | }
231 | do
232 | {
233 | if (len >= 2)
234 | {
235 | size_t lo, hi;
236 |
237 | lo = 0;
238 | hi = len - 1;
239 | while (1)
240 | {
241 | while (1)
242 | {
243 | if (lo >= hi)
244 | goto Ldone;
245 | if ((this)[lo] == true)
246 | break;
247 | lo++;
248 | }
249 |
250 | while (1)
251 | {
252 | if (lo >= hi)
253 | goto Ldone;
254 | if ((this)[hi] == false)
255 | break;
256 | hi--;
257 | }
258 |
259 | (this)[lo] = false;
260 | (this)[hi] = true;
261 |
262 | lo++;
263 | hi--;
264 | }
265 | Ldone:
266 | ;
267 | }
268 | return this;
269 | }
270 |
271 | unittest
272 | {
273 | debug(bitarray) printf("BitArray.sort.unittest\n");
274 |
275 | __gshared size_t x = 0b1100011000;
276 | __gshared BitArray ba = { 10, &x };
277 | ba.sort;
278 | for (size_t i = 0; i < 6; i++)
279 | assert(ba[i] == false);
280 | for (size_t i = 6; i < 10; i++)
281 | assert(ba[i] == true);
282 | }
283 |
284 |
285 | /***************************************
286 | * Support for operators == and != for bit arrays.
287 | */
288 |
289 | bool opEquals(const ref BitArray a2) const pure nothrow
290 | { size_t i;
291 |
292 | if (this.length != a2.length)
293 | return false; // not equal
294 | byte *p1 = cast(byte*)this.ptr;
295 | byte *p2 = cast(byte*)a2.ptr;
296 | auto n = this.length / 8;
297 | for (i = 0; i < n; i++)
298 | {
299 | if (p1[i] != p2[i])
300 | return false; // not equal
301 | }
302 |
303 | n = this.length & 7;
304 | auto mask = cast(ubyte)((1 << n) - 1);
305 | //printf("i = %d, n = %d, mask = %x, %x, %x\n", i, n, mask, p1[i], p2[i]);
306 | return (mask == 0) || (p1[i] & mask) == (p2[i] & mask);
307 | }
308 |
309 | unittest
310 | {
311 | debug(bitarray) printf("BitArray.opEquals unittest\n");
312 |
313 | static bool[] ba = [1,0,1,0,1];
314 | static bool[] bb = [1,0,1];
315 | static bool[] bc = [1,0,1,0,1,0,1];
316 | static bool[] bd = [1,0,1,1,1];
317 | static bool[] be = [1,0,1,0,1];
318 |
319 | BitArray a; a.init(ba);
320 | BitArray b; b.init(bb);
321 | BitArray c; c.init(bc);
322 | BitArray d; d.init(bd);
323 | BitArray e; e.init(be);
324 |
325 | assert(a != b);
326 | assert(a != c);
327 | assert(a != d);
328 | assert(a == e);
329 | }
330 |
331 | /***************************************
332 | * Implement comparison operators.
333 | */
334 |
335 | int opCmp(const ref BitArray a2) const pure nothrow
336 | {
337 | size_t i;
338 |
339 | auto len = this.length;
340 | if (a2.length < len)
341 | len = a2.length;
342 | auto p1 = cast(ubyte*)this.ptr;
343 | auto p2 = cast(ubyte*)a2.ptr;
344 | auto n = len / 8;
345 | for (i = 0; i < n; i++)
346 | {
347 | if (p1[i] != p2[i])
348 | break; // not equal
349 | }
350 | for (auto j = i * 8; j < len; j++)
351 | { auto mask = cast(ubyte)(1 << j);
352 |
353 | auto c = cast(int)(p1[i] & mask) - cast(int)(p2[i] & mask);
354 | if (c)
355 | return c;
356 | }
357 | version (D_LP64)
358 | {
359 | long c = this.len - a2.length;
360 | if (c < 0)
361 | return -1;
362 | else
363 | return c != 0;
364 | }
365 | else
366 | return cast(int)this.len - cast(int)a2.length;
367 | }
368 |
369 | unittest
370 | {
371 | debug(bitarray) printf("BitArray.opCmp unittest\n");
372 |
373 | static bool[] ba = [1,0,1,0,1];
374 | static bool[] bb = [1,0,1];
375 | static bool[] bc = [1,0,1,0,1,0,1];
376 | static bool[] bd = [1,0,1,1,1];
377 | static bool[] be = [1,0,1,0,1];
378 |
379 | BitArray a; a.init(ba);
380 | BitArray b; b.init(bb);
381 | BitArray c; c.init(bc);
382 | BitArray d; d.init(bd);
383 | BitArray e; e.init(be);
384 |
385 | assert(a > b);
386 | assert(a >= b);
387 | assert(a < c);
388 | assert(a <= c);
389 | assert(a < d);
390 | assert(a <= d);
391 | assert(a == e);
392 | assert(a <= e);
393 | assert(a >= e);
394 | }
395 |
396 | /***************************************
397 | * Set BitArray to contents of ba[]
398 | */
399 |
400 | void init(bool[] ba)
401 | {
402 | length = ba.length;
403 | foreach (i, b; ba)
404 | {
405 | (this)[i] = b;
406 | }
407 | }
408 |
409 |
410 | /***************************************
411 | * Map BitArray onto v[], with numbits being the number of bits
412 | * in the array. Does not copy the data.
413 | *
414 | * This is the inverse of opCast.
415 | */
416 | void init(void[] v, size_t numbits)
417 | in
418 | {
419 | assert(numbits <= v.length * 8);
420 | assert((v.length & 3) == 0);
421 | }
422 | do
423 | {
424 | ptr = cast(typeof(ptr))v.ptr;
425 | len = numbits;
426 | }
427 |
428 | unittest
429 | {
430 | debug(bitarray) printf("BitArray.init unittest\n");
431 |
432 | static bool[] ba = [1,0,1,0,1];
433 |
434 | BitArray a; a.init(ba);
435 | BitArray b;
436 | void[] v;
437 |
438 | v = cast(void[])a;
439 | b.init(v, a.length);
440 |
441 | assert(b[0] == 1);
442 | assert(b[1] == 0);
443 | assert(b[2] == 1);
444 | assert(b[3] == 0);
445 | assert(b[4] == 1);
446 |
447 | a[0] = 0;
448 | assert(b[0] == 0);
449 |
450 | assert(a == b);
451 | }
452 |
453 | /***************************************
454 | * Convert to void[].
455 | */
456 | void[] opCast()
457 | {
458 | return cast(void[])ptr[0 .. dim];
459 | }
460 |
461 | unittest
462 | {
463 | debug(bitarray) printf("BitArray.opCast unittest\n");
464 |
465 | static bool[] ba = [1,0,1,0,1];
466 |
467 | BitArray a; a.init(ba);
468 | void[] v = cast(void[])a;
469 |
470 | assert(v.length == a.dim * size_t.sizeof);
471 | }
472 |
473 | /***************************************
474 | * Support for unary operator ~ for bit arrays.
475 | */
476 | BitArray opUnary(string op : "~")()
477 | {
478 | auto dim = this.dim();
479 |
480 | BitArray result;
481 |
482 | result.length = len;
483 | for (size_t i = 0; i < dim; i++)
484 | result.ptr[i] = ~this.ptr[i];
485 | if (len & 31)
486 | result.ptr[dim - 1] &= ~(~0 << (len & 31));
487 | return result;
488 | }
489 |
490 | unittest
491 | {
492 | debug(bitarray) printf("BitArray.opUnary unittest\n");
493 |
494 | static bool[] ba = [1,0,1,0,1];
495 |
496 | BitArray a; a.init(ba);
497 | BitArray b = ~a;
498 |
499 | assert(b[0] == 0);
500 | assert(b[1] == 1);
501 | assert(b[2] == 0);
502 | assert(b[3] == 1);
503 | assert(b[4] == 0);
504 | }
505 |
506 |
507 | /***************************************
508 | * Support for binary operator & for bit arrays.
509 | */
510 | BitArray opBinary(string op : "&")(BitArray e2)
511 | in
512 | {
513 | assert(len == e2.length);
514 | }
515 | do
516 | {
517 | auto dim = this.dim();
518 |
519 | BitArray result;
520 |
521 | result.length = len;
522 | for (size_t i = 0; i < dim; i++)
523 | result.ptr[i] = this.ptr[i] & e2.ptr[i];
524 | return result;
525 | }
526 |
527 | unittest
528 | {
529 | debug(bitarray) printf("BitArray.opBinary unittest\n");
530 |
531 | static bool[] ba = [1,0,1,0,1];
532 | static bool[] bb = [1,0,1,1,0];
533 |
534 | BitArray a; a.init(ba);
535 | BitArray b; b.init(bb);
536 |
537 | BitArray c = a & b;
538 |
539 | assert(c[0] == 1);
540 | assert(c[1] == 0);
541 | assert(c[2] == 1);
542 | assert(c[3] == 0);
543 | assert(c[4] == 0);
544 | }
545 |
546 |
547 | /***************************************
548 | * Support for binary operator | for bit arrays.
549 | */
550 | BitArray opBinary(string op : "|")(BitArray e2)
551 | in
552 | {
553 | assert(len == e2.length);
554 | }
555 | do
556 | {
557 | auto dim = this.dim();
558 |
559 | BitArray result;
560 |
561 | result.length = len;
562 | for (size_t i = 0; i < dim; i++)
563 | result.ptr[i] = this.ptr[i] | e2.ptr[i];
564 | return result;
565 | }
566 |
567 | unittest
568 | {
569 | debug(bitarray) printf("BitArray.opBinary unittest\n");
570 |
571 | static bool[] ba = [1,0,1,0,1];
572 | static bool[] bb = [1,0,1,1,0];
573 |
574 | BitArray a; a.init(ba);
575 | BitArray b; b.init(bb);
576 |
577 | BitArray c = a | b;
578 |
579 | assert(c[0] == 1);
580 | assert(c[1] == 0);
581 | assert(c[2] == 1);
582 | assert(c[3] == 1);
583 | assert(c[4] == 1);
584 | }
585 |
586 |
587 | /***************************************
588 | * Support for binary operator ^ for bit arrays.
589 | */
590 | BitArray opBinary(string op : "^")(BitArray e2)
591 | in
592 | {
593 | assert(len == e2.length);
594 | }
595 | do
596 | {
597 | auto dim = this.dim();
598 |
599 | BitArray result;
600 |
601 | result.length = len;
602 | for (size_t i = 0; i < dim; i++)
603 | result.ptr[i] = this.ptr[i] ^ e2.ptr[i];
604 | return result;
605 | }
606 |
607 | unittest
608 | {
609 | debug(bitarray) printf("BitArray.opBinary unittest\n");
610 |
611 | static bool[] ba = [1,0,1,0,1];
612 | static bool[] bb = [1,0,1,1,0];
613 |
614 | BitArray a; a.init(ba);
615 | BitArray b; b.init(bb);
616 |
617 | BitArray c = a ^ b;
618 |
619 | assert(c[0] == 0);
620 | assert(c[1] == 0);
621 | assert(c[2] == 0);
622 | assert(c[3] == 1);
623 | assert(c[4] == 1);
624 | }
625 |
626 |
627 | /***************************************
628 | * Support for binary operator - for bit arrays.
629 | *
630 | * $(I a - b) for BitArrays means the same thing as $(I a & ~b).
631 | */
632 | BitArray opBinary(string op : "-")(BitArray e2)
633 | in
634 | {
635 | assert(len == e2.length);
636 | }
637 | do
638 | {
639 | auto dim = this.dim();
640 |
641 | BitArray result;
642 |
643 | result.length = len;
644 | for (size_t i = 0; i < dim; i++)
645 | result.ptr[i] = this.ptr[i] & ~e2.ptr[i];
646 | return result;
647 | }
648 |
649 | unittest
650 | {
651 | debug(bitarray) printf("BitArray.opBinary unittest\n");
652 |
653 | static bool[] ba = [1,0,1,0,1];
654 | static bool[] bb = [1,0,1,1,0];
655 |
656 | BitArray a; a.init(ba);
657 | BitArray b; b.init(bb);
658 |
659 | BitArray c = a - b;
660 |
661 | assert(c[0] == 0);
662 | assert(c[1] == 0);
663 | assert(c[2] == 0);
664 | assert(c[3] == 0);
665 | assert(c[4] == 1);
666 | }
667 |
668 |
669 | /***************************************
670 | * Support for operator &= bit arrays.
671 | */
672 | BitArray opOpAssign(string op : "&")(BitArray e2)
673 | in
674 | {
675 | assert(len == e2.length);
676 | }
677 | do
678 | {
679 | auto dim = this.dim();
680 |
681 | for (size_t i = 0; i < dim; i++)
682 | ptr[i] &= e2.ptr[i];
683 | return this;
684 | }
685 |
686 | unittest
687 | {
688 | debug(bitarray) printf("BitArray.opOpAssign unittest\n");
689 |
690 | static bool[] ba = [1,0,1,0,1];
691 | static bool[] bb = [1,0,1,1,0];
692 |
693 | BitArray a; a.init(ba);
694 | BitArray b; b.init(bb);
695 |
696 | a &= b;
697 | assert(a[0] == 1);
698 | assert(a[1] == 0);
699 | assert(a[2] == 1);
700 | assert(a[3] == 0);
701 | assert(a[4] == 0);
702 | }
703 |
704 |
705 | /***************************************
706 | * Support for operator |= for bit arrays.
707 | */
708 | BitArray opOpAssign(string op : "|")(BitArray e2)
709 | in
710 | {
711 | assert(len == e2.length);
712 | }
713 | do
714 | {
715 | auto dim = this.dim();
716 |
717 | for (size_t i = 0; i < dim; i++)
718 | ptr[i] |= e2.ptr[i];
719 | return this;
720 | }
721 |
722 | unittest
723 | {
724 | debug(bitarray) printf("BitArray.opOpAssign unittest\n");
725 |
726 | static bool[] ba = [1,0,1,0,1];
727 | static bool[] bb = [1,0,1,1,0];
728 |
729 | BitArray a; a.init(ba);
730 | BitArray b; b.init(bb);
731 |
732 | a |= b;
733 | assert(a[0] == 1);
734 | assert(a[1] == 0);
735 | assert(a[2] == 1);
736 | assert(a[3] == 1);
737 | assert(a[4] == 1);
738 | }
739 |
740 | /***************************************
741 | * Support for operator ^= for bit arrays.
742 | */
743 | BitArray opOpAssign(string op : "^")(BitArray e2)
744 | in
745 | {
746 | assert(len == e2.length);
747 | }
748 | do
749 | {
750 | auto dim = this.dim();
751 |
752 | for (size_t i = 0; i < dim; i++)
753 | ptr[i] ^= e2.ptr[i];
754 | return this;
755 | }
756 |
757 | unittest
758 | {
759 | debug(bitarray) printf("BitArray.opOpAssign unittest\n");
760 |
761 | static bool[] ba = [1,0,1,0,1];
762 | static bool[] bb = [1,0,1,1,0];
763 |
764 | BitArray a; a.init(ba);
765 | BitArray b; b.init(bb);
766 |
767 | a ^= b;
768 | assert(a[0] == 0);
769 | assert(a[1] == 0);
770 | assert(a[2] == 0);
771 | assert(a[3] == 1);
772 | assert(a[4] == 1);
773 | }
774 |
775 | /***************************************
776 | * Support for operator -= for bit arrays.
777 | *
778 | * $(I a -= b) for BitArrays means the same thing as $(I a &= ~b).
779 | */
780 | BitArray opOpAssign(string op : "-")(BitArray e2)
781 | in
782 | {
783 | assert(len == e2.length);
784 | }
785 | do
786 | {
787 | auto dim = this.dim();
788 |
789 | for (size_t i = 0; i < dim; i++)
790 | ptr[i] &= ~e2.ptr[i];
791 | return this;
792 | }
793 |
794 | unittest
795 | {
796 | debug(bitarray) printf("BitArray.opOpAssign unittest\n");
797 |
798 | static bool[] ba = [1,0,1,0,1];
799 | static bool[] bb = [1,0,1,1,0];
800 |
801 | BitArray a; a.init(ba);
802 | BitArray b; b.init(bb);
803 |
804 | a -= b;
805 | assert(a[0] == 0);
806 | assert(a[1] == 0);
807 | assert(a[2] == 0);
808 | assert(a[3] == 0);
809 | assert(a[4] == 1);
810 | }
811 |
812 | /***************************************
813 | * Support for operator ~= for bit arrays.
814 | */
815 |
816 | BitArray opOpAssign(string op : "~")(bool b)
817 | {
818 | length = len + 1;
819 | (this)[len - 1] = b;
820 | return this;
821 | }
822 |
823 | unittest
824 | {
825 | debug(bitarray) printf("BitArray.opOpAssign unittest\n");
826 |
827 | static bool[] ba = [1,0,1,0,1];
828 |
829 | BitArray a; a.init(ba);
830 | BitArray b;
831 |
832 | b = (a ~= true);
833 | assert(a[0] == 1);
834 | assert(a[1] == 0);
835 | assert(a[2] == 1);
836 | assert(a[3] == 0);
837 | assert(a[4] == 1);
838 | assert(a[5] == 1);
839 |
840 | assert(b == a);
841 | }
842 |
843 | /***************************************
844 | * ditto
845 | */
846 |
847 | BitArray opOpAssign(string op : "~")(BitArray b)
848 | {
849 | auto istart = len;
850 | length = len + b.length;
851 | for (auto i = istart; i < len; i++)
852 | (this)[i] = b[i - istart];
853 | return this;
854 | }
855 |
856 | unittest
857 | {
858 | debug(bitarray) printf("BitArray.opOpAssign unittest\n");
859 |
860 | static bool[] ba = [1,0];
861 | static bool[] bb = [0,1,0];
862 |
863 | BitArray a; a.init(ba);
864 | BitArray b; b.init(bb);
865 | BitArray c;
866 |
867 | c = (a ~= b);
868 | assert(a.length == 5);
869 | assert(a[0] == 1);
870 | assert(a[1] == 0);
871 | assert(a[2] == 0);
872 | assert(a[3] == 1);
873 | assert(a[4] == 0);
874 |
875 | assert(c == a);
876 | }
877 |
878 | /***************************************
879 | * Support for binary operator ~ for bit arrays.
880 | */
881 | BitArray opBinary(string op : "~")(bool b)
882 | {
883 | auto r = this.dup;
884 | r.length = len + 1;
885 | r[len] = b;
886 | return r;
887 | }
888 |
889 | /** ditto */
890 | BitArray opBinaryRight(string op : "~")(bool b)
891 | {
892 | BitArray r;
893 |
894 | r.length = len + 1;
895 | r[0] = b;
896 | for (size_t i = 0; i < len; i++)
897 | r[1 + i] = (this)[i];
898 | return r;
899 | }
900 |
901 | /** ditto */
902 | BitArray opBinary(string op : "~")(BitArray b)
903 | {
904 | BitArray r;
905 |
906 | r = this.dup();
907 | r ~= b;
908 | return r;
909 | }
910 |
911 | unittest
912 | {
913 | debug(bitarray) printf("BitArray.opBinary unittest\n");
914 |
915 | static bool[] ba = [1,0];
916 | static bool[] bb = [0,1,0];
917 |
918 | BitArray a; a.init(ba);
919 | BitArray b; b.init(bb);
920 | BitArray c;
921 |
922 | c = (a ~ b);
923 | assert(c.length == 5);
924 | assert(c[0] == 1);
925 | assert(c[1] == 0);
926 | assert(c[2] == 0);
927 | assert(c[3] == 1);
928 | assert(c[4] == 0);
929 |
930 | c = (a ~ true);
931 | assert(c.length == 3);
932 | assert(c[0] == 1);
933 | assert(c[1] == 0);
934 | assert(c[2] == 1);
935 |
936 | c = (false ~ a);
937 | assert(c.length == 3);
938 | assert(c[0] == 0);
939 | assert(c[1] == 1);
940 | assert(c[2] == 0);
941 | }
942 | }
943 |
--------------------------------------------------------------------------------
/src/undead/signals.d:
--------------------------------------------------------------------------------
1 | // Written in the D programming language.
2 |
3 | /**
4 | * Signals and Slots are an implementation of the Observer Pattern.
5 | * Essentially, when a Signal is emitted, a list of connected Observers
6 | * (called slots) are called.
7 | *
8 | * There have been several D implementations of Signals and Slots.
9 | * This version makes use of several new features in D, which make
10 | * using it simpler and less error prone. In particular, it is no
11 | * longer necessary to instrument the slots.
12 | *
13 | * References:
14 | * $(LUCKY A Deeper Look at Signals and Slots)$(BR)
15 | * $(LINK2 http://en.wikipedia.org/wiki/Observer_pattern, Observer pattern)$(BR)
16 | * $(LINK2 http://en.wikipedia.org/wiki/Signals_and_slots, Wikipedia)$(BR)
17 | * $(LINK2 http://boost.org/doc/html/$(SIGNALS).html, Boost Signals)$(BR)
18 | * $(LINK2 http://qt-project.org/doc/qt-5/signalsandslots.html, Qt)$(BR)
19 | *
20 | * There has been a great deal of discussion in the D newsgroups
21 | * over this, and several implementations:
22 | *
23 | * $(LINK2 http://www.digitalmars.com/d/archives/digitalmars/D/announce/signal_slots_library_4825.html, signal slots library)$(BR)
24 | * $(LINK2 http://www.digitalmars.com/d/archives/digitalmars/D/Signals_and_Slots_in_D_42387.html, Signals and Slots in D)$(BR)
25 | * $(LINK2 http://www.digitalmars.com/d/archives/digitalmars/D/Dynamic_binding_--_Qt_s_Signals_and_Slots_vs_Objective-C_42260.html, Dynamic binding -- Qt's Signals and Slots vs Objective-C)$(BR)
26 | * $(LINK2 http://www.digitalmars.com/d/archives/digitalmars/D/Dissecting_the_SS_42377.html, Dissecting the SS)$(BR)
27 | * $(LINK2 http://www.digitalmars.com/d/archives/digitalmars/D/dwt/about_harmonia_454.html, about harmonia)$(BR)
28 | * $(LINK2 http://www.digitalmars.com/d/archives/digitalmars/D/announce/1502.html, Another event handling module)$(BR)
29 | * $(LINK2 http://www.digitalmars.com/d/archives/digitalmars/D/41825.html, Suggestion: signal/slot mechanism)$(BR)
30 | * $(LINK2 http://www.digitalmars.com/d/archives/digitalmars/D/13251.html, Signals and slots?)$(BR)
31 | * $(LINK2 http://www.digitalmars.com/d/archives/digitalmars/D/10714.html, Signals and slots ready for evaluation)$(BR)
32 | * $(LINK2 http://www.digitalmars.com/d/archives/digitalmars/D/1393.html, Signals & Slots for Walter)$(BR)
33 | * $(LINK2 http://www.digitalmars.com/d/archives/28456.html, Signal/Slot mechanism?)$(BR)
34 | * $(LINK2 http://www.digitalmars.com/d/archives/19470.html, Modern Features?)$(BR)
35 | * $(LINK2 http://www.digitalmars.com/d/archives/16592.html, Delegates vs interfaces)$(BR)
36 | * $(LINK2 http://www.digitalmars.com/d/archives/16583.html, The importance of component programming (properties$(COMMA) signals and slots$(COMMA) etc))$(BR)
37 | * $(LINK2 http://www.digitalmars.com/d/archives/16368.html, signals and slots)$(BR)
38 | *
39 | * Bugs:
40 | * $(RED Slots can only be delegates formed from class objects or
41 | * interfaces to class objects. If a delegate to something else
42 | * is passed to connect(), such as a struct member function,
43 | * a nested function, a COM interface or a closure, undefined behavior
44 | * will result.)
45 | *
46 | * Not safe for multiple threads operating on the same signals
47 | * or slots.
48 | * Macros:
49 | * SIGNALS=signals
50 | *
51 | * Copyright: Copyright The D Language Foundation 2000 - 2009.
52 | * License: $(HTTP www.boost.org/LICENSE_1_0.txt, Boost License 1.0).
53 | * Authors: $(HTTP digitalmars.com, Walter Bright)
54 | * Source: $(PHOBOSSRC std/signals.d)
55 | *
56 | * $(SCRIPT inhibitQuickIndex = 1;)
57 | */
58 | /* Copyright The D Language Foundation 2000 - 2009.
59 | * Distributed under the Boost Software License, Version 1.0.
60 | * (See accompanying file LICENSE_1_0.txt or copy at
61 | * http://www.boost.org/LICENSE_1_0.txt)
62 | */
63 | module std.signals;
64 |
65 | import core.exception : onOutOfMemoryError;
66 | import core.stdc.stdlib : calloc, realloc, free;
67 | import std.stdio;
68 |
69 | // Special function for internal use only.
70 | // Use of this is where the slot had better be a delegate
71 | // to an object or an interface that is part of an object.
72 | extern (C) Object _d_toObject(void* p);
73 |
74 | // Used in place of Object.notifyRegister and Object.notifyUnRegister.
75 | alias DisposeEvt = void delegate(Object);
76 | extern (C) void rt_attachDisposeEvent( Object obj, DisposeEvt evt );
77 | extern (C) void rt_detachDisposeEvent( Object obj, DisposeEvt evt );
78 | //debug=signal;
79 |
80 | /************************
81 | * Mixin to create a signal within a class object.
82 | *
83 | * Different signals can be added to a class by naming the mixins.
84 | */
85 |
86 | mixin template Signal(T1...)
87 | {
88 | static import core.exception;
89 | static import core.stdc.stdlib;
90 | /***
91 | * A slot is implemented as a delegate.
92 | * The slot_t is the type of the delegate.
93 | * The delegate must be to an instance of a class or an interface
94 | * to a class instance.
95 | * Delegates to struct instances or nested functions must not be
96 | * used as slots.
97 | */
98 | alias slot_t = void delegate(T1);
99 |
100 | /***
101 | * Call each of the connected slots, passing the argument(s) i to them.
102 | * Nested call will be ignored.
103 | */
104 | final void emit( T1 i )
105 | {
106 | if (status >= ST.inemitting || !slots.length)
107 | return; // should not nest
108 |
109 | status = ST.inemitting;
110 | scope (exit)
111 | status = ST.idle;
112 |
113 | foreach (slot; slots[0 .. slots_idx])
114 | { if (slot)
115 | slot(i);
116 | }
117 |
118 | assert(status >= ST.inemitting);
119 | if (status == ST.inemitting_disconnected)
120 | {
121 | for (size_t j = 0; j < slots_idx;)
122 | {
123 | if (slots[j] is null)
124 | {
125 | slots_idx--;
126 | slots[j] = slots[slots_idx];
127 | }
128 | else
129 | j++;
130 | }
131 | }
132 | }
133 |
134 | /***
135 | * Add a slot to the list of slots to be called when emit() is called.
136 | */
137 | final void connect(slot_t slot)
138 | {
139 | /* Do this:
140 | * slots ~= slot;
141 | * but use malloc() and friends instead
142 | */
143 | auto len = slots.length;
144 | if (slots_idx == len)
145 | {
146 | if (slots.length == 0)
147 | {
148 | len = 4;
149 | auto p = core.stdc.stdlib.calloc(slot_t.sizeof, len);
150 | if (!p)
151 | core.exception.onOutOfMemoryError();
152 | slots = (cast(slot_t*) p)[0 .. len];
153 | }
154 | else
155 | {
156 | import core.checkedint : addu, mulu;
157 | bool overflow;
158 | len = addu(mulu(len, 2, overflow), 4, overflow); // len = len * 2 + 4
159 | const nbytes = mulu(len, slot_t.sizeof, overflow);
160 | if (overflow) assert(0);
161 |
162 | auto p = core.stdc.stdlib.realloc(slots.ptr, nbytes);
163 | if (!p)
164 | core.exception.onOutOfMemoryError();
165 | slots = (cast(slot_t*) p)[0 .. len];
166 | slots[slots_idx + 1 .. $] = null;
167 | }
168 | }
169 | slots[slots_idx++] = slot;
170 |
171 | L1:
172 | Object o = _d_toObject(slot.ptr);
173 | rt_attachDisposeEvent(o, &unhook);
174 | }
175 |
176 | /***
177 | * Remove a slot from the list of slots to be called when emit() is called.
178 | */
179 | final void disconnect(slot_t slot)
180 | {
181 | debug (signal) writefln("Signal.disconnect(slot)");
182 | size_t disconnectedSlots = 0;
183 | size_t instancePreviousSlots = 0;
184 | if (status >= ST.inemitting)
185 | {
186 | foreach (i, sloti; slots[0 .. slots_idx])
187 | {
188 | if (sloti.ptr == slot.ptr &&
189 | ++instancePreviousSlots &&
190 | sloti == slot)
191 | {
192 | disconnectedSlots++;
193 | slots[i] = null;
194 | status = ST.inemitting_disconnected;
195 | }
196 | }
197 | }
198 | else
199 | {
200 | for (size_t i = 0; i < slots_idx; )
201 | {
202 | if (slots[i].ptr == slot.ptr &&
203 | ++instancePreviousSlots &&
204 | slots[i] == slot)
205 | {
206 | slots_idx--;
207 | disconnectedSlots++;
208 | slots[i] = slots[slots_idx];
209 | slots[slots_idx] = null; // not strictly necessary
210 | }
211 | else
212 | i++;
213 | }
214 | }
215 |
216 | // detach object from dispose event if all its slots have been removed
217 | if (instancePreviousSlots == disconnectedSlots)
218 | {
219 | Object o = _d_toObject(slot.ptr);
220 | rt_detachDisposeEvent(o, &unhook);
221 | }
222 | }
223 |
224 | /***
225 | * Disconnect all the slots.
226 | */
227 | final void disconnectAll()
228 | {
229 | debug (signal) writefln("Signal.disconnectAll");
230 | __dtor();
231 | slots_idx = 0;
232 | status = ST.idle;
233 | }
234 |
235 | /* **
236 | * Special function called when o is destroyed.
237 | * It causes any slots dependent on o to be removed from the list
238 | * of slots to be called by emit().
239 | */
240 | final void unhook(Object o)
241 | in { assert( status == ST.idle ); }
242 | do
243 | {
244 | debug (signal) writefln("Signal.unhook(o = %s)", cast(void*) o);
245 | for (size_t i = 0; i < slots_idx; )
246 | {
247 | if (_d_toObject(slots[i].ptr) is o)
248 | { slots_idx--;
249 | slots[i] = slots[slots_idx];
250 | slots[slots_idx] = null; // not strictly necessary
251 | }
252 | else
253 | i++;
254 | }
255 | }
256 |
257 | /* **
258 | * There can be multiple destructors inserted by mixins.
259 | */
260 | ~this()
261 | {
262 | /* **
263 | * When this object is destroyed, need to let every slot
264 | * know that this object is destroyed so they are not left
265 | * with dangling references to it.
266 | */
267 | if (slots.length)
268 | {
269 | foreach (slot; slots[0 .. slots_idx])
270 | {
271 | if (slot)
272 | { Object o = _d_toObject(slot.ptr);
273 | rt_detachDisposeEvent(o, &unhook);
274 | }
275 | }
276 | core.stdc.stdlib.free(slots.ptr);
277 | slots = null;
278 | }
279 | }
280 |
281 | private:
282 | slot_t[] slots; // the slots to call from emit()
283 | size_t slots_idx; // used length of slots[]
284 |
285 | enum ST { idle, inemitting, inemitting_disconnected }
286 | ST status;
287 | }
288 |
289 | ///
290 | @system unittest
291 | {
292 | import std.signals;
293 |
294 | int observedMessageCounter = 0;
295 |
296 | class Observer
297 | { // our slot
298 | void watch(string msg, int value)
299 | {
300 | switch (observedMessageCounter++)
301 | {
302 | case 0:
303 | assert(msg == "setting new value");
304 | assert(value == 4);
305 | break;
306 | case 1:
307 | assert(msg == "setting new value");
308 | assert(value == 6);
309 | break;
310 | default:
311 | assert(0, "Unknown observation");
312 | }
313 | }
314 | }
315 |
316 | class Observer2
317 | { // our slot
318 | void watch(string msg, int value)
319 | {
320 | }
321 | }
322 |
323 | class Foo
324 | {
325 | int value() { return _value; }
326 |
327 | int value(int v)
328 | {
329 | if (v != _value)
330 | { _value = v;
331 | // call all the connected slots with the two parameters
332 | emit("setting new value", v);
333 | }
334 | return v;
335 | }
336 |
337 | // Mix in all the code we need to make Foo into a signal
338 | mixin Signal!(string, int);
339 |
340 | private :
341 | int _value;
342 | }
343 |
344 | Foo a = new Foo;
345 | Observer o = new Observer;
346 | auto o2 = new Observer2;
347 | auto o3 = new Observer2;
348 | auto o4 = new Observer2;
349 | auto o5 = new Observer2;
350 |
351 | a.value = 3; // should not call o.watch()
352 | a.connect(&o.watch); // o.watch is the slot
353 | a.connect(&o2.watch);
354 | a.connect(&o3.watch);
355 | a.connect(&o4.watch);
356 | a.connect(&o5.watch);
357 | a.value = 4; // should call o.watch()
358 | a.disconnect(&o.watch); // o.watch is no longer a slot
359 | a.disconnect(&o3.watch);
360 | a.disconnect(&o5.watch);
361 | a.disconnect(&o4.watch);
362 | a.disconnect(&o2.watch);
363 | a.value = 5; // so should not call o.watch()
364 | a.connect(&o2.watch);
365 | a.connect(&o.watch); // connect again
366 | a.value = 6; // should call o.watch()
367 | destroy(o); // destroying o should automatically disconnect it
368 | a.value = 7; // should not call o.watch()
369 |
370 | assert(observedMessageCounter == 2);
371 | }
372 |
373 | // A function whose sole purpose is to get this module linked in
374 | // so the unittest will run.
375 | void linkin() { }
376 |
377 | @system unittest
378 | {
379 | class Observer
380 | {
381 | void watch(string msg, int i)
382 | {
383 | //writefln("Observed msg '%s' and value %s", msg, i);
384 | captured_value = i;
385 | captured_msg = msg;
386 | }
387 |
388 | int captured_value;
389 | string captured_msg;
390 | }
391 |
392 | class Foo
393 | {
394 | @property int value() { return _value; }
395 |
396 | @property int value(int v)
397 | {
398 | if (v != _value)
399 | { _value = v;
400 | emit("setting new value", v);
401 | }
402 | return v;
403 | }
404 |
405 | mixin Signal!(string, int);
406 |
407 | private:
408 | int _value;
409 | }
410 |
411 | Foo a = new Foo;
412 | Observer o = new Observer;
413 |
414 | // check initial condition
415 | assert(o.captured_value == 0);
416 | assert(o.captured_msg == "");
417 |
418 | // set a value while no observation is in place
419 | a.value = 3;
420 | assert(o.captured_value == 0);
421 | assert(o.captured_msg == "");
422 |
423 | // connect the watcher and trigger it
424 | a.connect(&o.watch);
425 | a.value = 4;
426 | assert(o.captured_value == 4);
427 | assert(o.captured_msg == "setting new value");
428 |
429 | // disconnect the watcher and make sure it doesn't trigger
430 | a.disconnect(&o.watch);
431 | a.value = 5;
432 | assert(o.captured_value == 4);
433 | assert(o.captured_msg == "setting new value");
434 |
435 | // reconnect the watcher and make sure it triggers
436 | a.connect(&o.watch);
437 | a.value = 6;
438 | assert(o.captured_value == 6);
439 | assert(o.captured_msg == "setting new value");
440 |
441 | // destroy the underlying object and make sure it doesn't cause
442 | // a crash or other problems
443 | destroy(o);
444 | a.value = 7;
445 | }
446 |
447 | @system unittest
448 | {
449 | class Observer
450 | {
451 | int i;
452 | long l;
453 | string str;
454 |
455 | void watchInt(string str, int i)
456 | {
457 | this.str = str;
458 | this.i = i;
459 | }
460 |
461 | void watchLong(string str, long l)
462 | {
463 | this.str = str;
464 | this.l = l;
465 | }
466 | }
467 |
468 | class Bar
469 | {
470 | @property void value1(int v) { s1.emit("str1", v); }
471 | @property void value2(int v) { s2.emit("str2", v); }
472 | @property void value3(long v) { s3.emit("str3", v); }
473 |
474 | mixin Signal!(string, int) s1;
475 | mixin Signal!(string, int) s2;
476 | mixin Signal!(string, long) s3;
477 | }
478 |
479 | void test(T)(T a) {
480 | auto o1 = new Observer;
481 | auto o2 = new Observer;
482 | auto o3 = new Observer;
483 |
484 | // connect the watcher and trigger it
485 | a.s1.connect(&o1.watchInt);
486 | a.s2.connect(&o2.watchInt);
487 | a.s3.connect(&o3.watchLong);
488 |
489 | assert(!o1.i && !o1.l && o1.str == null);
490 | assert(!o2.i && !o2.l && o2.str == null);
491 | assert(!o3.i && !o3.l && o3.str == null);
492 |
493 | a.value1 = 11;
494 | assert(o1.i == 11 && !o1.l && o1.str == "str1");
495 | assert(!o2.i && !o2.l && o2.str == null);
496 | assert(!o3.i && !o3.l && o3.str == null);
497 | o1.i = -11; o1.str = "x1";
498 |
499 | a.value2 = 12;
500 | assert(o1.i == -11 && !o1.l && o1.str == "x1");
501 | assert(o2.i == 12 && !o2.l && o2.str == "str2");
502 | assert(!o3.i && !o3.l && o3.str == null);
503 | o2.i = -12; o2.str = "x2";
504 |
505 | a.value3 = 13;
506 | assert(o1.i == -11 && !o1.l && o1.str == "x1");
507 | assert(o2.i == -12 && !o1.l && o2.str == "x2");
508 | assert(!o3.i && o3.l == 13 && o3.str == "str3");
509 | o3.l = -13; o3.str = "x3";
510 |
511 | // disconnect the watchers and make sure it doesn't trigger
512 | a.s1.disconnect(&o1.watchInt);
513 | a.s2.disconnect(&o2.watchInt);
514 | a.s3.disconnect(&o3.watchLong);
515 |
516 | a.value1 = 21;
517 | a.value2 = 22;
518 | a.value3 = 23;
519 | assert(o1.i == -11 && !o1.l && o1.str == "x1");
520 | assert(o2.i == -12 && !o1.l && o2.str == "x2");
521 | assert(!o3.i && o3.l == -13 && o3.str == "x3");
522 |
523 | // reconnect the watcher and make sure it triggers
524 | a.s1.connect(&o1.watchInt);
525 | a.s2.connect(&o2.watchInt);
526 | a.s3.connect(&o3.watchLong);
527 |
528 | a.value1 = 31;
529 | a.value2 = 32;
530 | a.value3 = 33;
531 | assert(o1.i == 31 && !o1.l && o1.str == "str1");
532 | assert(o2.i == 32 && !o1.l && o2.str == "str2");
533 | assert(!o3.i && o3.l == 33 && o3.str == "str3");
534 |
535 | // destroy observers
536 | destroy(o1);
537 | destroy(o2);
538 | destroy(o3);
539 | a.value1 = 41;
540 | a.value2 = 42;
541 | a.value3 = 43;
542 | }
543 |
544 | test(new Bar);
545 |
546 | class BarDerived: Bar
547 | {
548 | @property void value4(int v) { s4.emit("str4", v); }
549 | @property void value5(int v) { s5.emit("str5", v); }
550 | @property void value6(long v) { s6.emit("str6", v); }
551 |
552 | mixin Signal!(string, int) s4;
553 | mixin Signal!(string, int) s5;
554 | mixin Signal!(string, long) s6;
555 | }
556 |
557 | auto a = new BarDerived;
558 |
559 | test!Bar(a);
560 | test!BarDerived(a);
561 |
562 | auto o4 = new Observer;
563 | auto o5 = new Observer;
564 | auto o6 = new Observer;
565 |
566 | // connect the watcher and trigger it
567 | a.s4.connect(&o4.watchInt);
568 | a.s5.connect(&o5.watchInt);
569 | a.s6.connect(&o6.watchLong);
570 |
571 | assert(!o4.i && !o4.l && o4.str == null);
572 | assert(!o5.i && !o5.l && o5.str == null);
573 | assert(!o6.i && !o6.l && o6.str == null);
574 |
575 | a.value4 = 44;
576 | assert(o4.i == 44 && !o4.l && o4.str == "str4");
577 | assert(!o5.i && !o5.l && o5.str == null);
578 | assert(!o6.i && !o6.l && o6.str == null);
579 | o4.i = -44; o4.str = "x4";
580 |
581 | a.value5 = 45;
582 | assert(o4.i == -44 && !o4.l && o4.str == "x4");
583 | assert(o5.i == 45 && !o5.l && o5.str == "str5");
584 | assert(!o6.i && !o6.l && o6.str == null);
585 | o5.i = -45; o5.str = "x5";
586 |
587 | a.value6 = 46;
588 | assert(o4.i == -44 && !o4.l && o4.str == "x4");
589 | assert(o5.i == -45 && !o4.l && o5.str == "x5");
590 | assert(!o6.i && o6.l == 46 && o6.str == "str6");
591 | o6.l = -46; o6.str = "x6";
592 |
593 | // disconnect the watchers and make sure it doesn't trigger
594 | a.s4.disconnect(&o4.watchInt);
595 | a.s5.disconnect(&o5.watchInt);
596 | a.s6.disconnect(&o6.watchLong);
597 |
598 | a.value4 = 54;
599 | a.value5 = 55;
600 | a.value6 = 56;
601 | assert(o4.i == -44 && !o4.l && o4.str == "x4");
602 | assert(o5.i == -45 && !o4.l && o5.str == "x5");
603 | assert(!o6.i && o6.l == -46 && o6.str == "x6");
604 |
605 | // reconnect the watcher and make sure it triggers
606 | a.s4.connect(&o4.watchInt);
607 | a.s5.connect(&o5.watchInt);
608 | a.s6.connect(&o6.watchLong);
609 |
610 | a.value4 = 64;
611 | a.value5 = 65;
612 | a.value6 = 66;
613 | assert(o4.i == 64 && !o4.l && o4.str == "str4");
614 | assert(o5.i == 65 && !o4.l && o5.str == "str5");
615 | assert(!o6.i && o6.l == 66 && o6.str == "str6");
616 |
617 | // destroy observers
618 | destroy(o4);
619 | destroy(o5);
620 | destroy(o6);
621 | a.value4 = 44;
622 | a.value5 = 45;
623 | a.value6 = 46;
624 | }
625 |
626 | // Triggers bug from issue 15341
627 | @system unittest
628 | {
629 | class Observer
630 | {
631 | void watch() { }
632 | void watch2() { }
633 | }
634 |
635 | class Bar
636 | {
637 | mixin Signal!();
638 | }
639 |
640 | auto a = new Bar;
641 | auto o = new Observer;
642 |
643 | //Connect both observer methods for the same instance
644 | a.connect(&o.watch);
645 | a.connect(&o.watch2); // not connecting watch2() or disconnecting it manually fixes the issue
646 |
647 | //Disconnect a single method of the two
648 | a.disconnect(&o.watch); // NOT disconnecting watch() fixes the issue
649 |
650 | destroy(o); // destroying o should automatically call unhook and disconnect the slot for watch2
651 | a.emit(); // should not raise segfault since &o.watch2 is no longer connected
652 | }
653 |
654 | version (none) // Disabled because of https://issues.dlang.org/show_bug.cgi?id=5028
655 | @system unittest
656 | {
657 | class A
658 | {
659 | mixin Signal!(string, int) s1;
660 | }
661 |
662 | class B : A
663 | {
664 | mixin Signal!(string, int) s2;
665 | }
666 | }
667 |
668 | // Triggers bug from issue 16249
669 | @system unittest
670 | {
671 | class myLINE
672 | {
673 | mixin Signal!( myLINE, int );
674 |
675 | void value( int v )
676 | {
677 | if ( v >= 0 ) emit( this, v );
678 | else emit( new myLINE, v );
679 | }
680 | }
681 |
682 | class Dot
683 | {
684 | int value;
685 |
686 | myLINE line_;
687 | void line( myLINE line_x )
688 | {
689 | if ( line_ is line_x ) return;
690 |
691 | if ( line_ !is null )
692 | {
693 | line_.disconnect( &watch );
694 | }
695 | line_ = line_x;
696 | line_.connect( &watch );
697 | }
698 |
699 | void watch( myLINE line_x, int value_x )
700 | {
701 | line = line_x;
702 | value = value_x;
703 | }
704 | }
705 |
706 | auto dot1 = new Dot;
707 | auto dot2 = new Dot;
708 | auto line = new myLINE;
709 | dot1.line = line;
710 | dot2.line = line;
711 |
712 | line.value = 11;
713 | assert( dot1.value == 11 );
714 | assert( dot2.value == 11 );
715 |
716 | line.value = -22;
717 | assert( dot1.value == -22 );
718 | assert( dot2.value == -22 );
719 | }
720 |
721 | @system unittest
722 | {
723 | import std.signals;
724 |
725 | class Observer
726 | { // our slot
727 | void watch(string msg, int value)
728 | {
729 | if (value != 0)
730 | {
731 | assert(msg == "setting new value");
732 | assert(value == 1);
733 | }
734 | }
735 | }
736 |
737 | class Foo
738 | {
739 | int value() { return _value; }
740 |
741 | int value(int v)
742 | {
743 | if (v != _value)
744 | {
745 | _value = v;
746 | // call all the connected slots with the parameters
747 | emit("setting new value", v);
748 | }
749 | return v;
750 | }
751 |
752 | // Mix in all the code we need to make Foo into a signal
753 | mixin Signal!(string, int);
754 |
755 | private :
756 | int _value;
757 | }
758 |
759 | Foo a = new Foo;
760 | Observer o = new Observer;
761 | auto o2 = new Observer;
762 |
763 | a.value = 3; // should not call o.watch()
764 | a.connect(&o.watch); // o.watch is the slot
765 | a.connect(&o2.watch);
766 | a.value = 1; // should call o.watch()
767 | a.disconnectAll();
768 | a.value = 5; // so should not call o.watch()
769 | a.connect(&o.watch); // connect again
770 | a.connect(&o2.watch);
771 | a.value = 1; // should call o.watch()
772 | destroy(o); // destroying o should automatically disconnect it
773 | destroy(o2);
774 | a.value = 7; // should not call o.watch()
775 | }
776 |
--------------------------------------------------------------------------------
/src/undead/dateparse.d:
--------------------------------------------------------------------------------
1 | // Written in the D programming language.
2 |
3 | /**
4 | * $(RED Deprecated. It will be removed in February 2012.
5 | * Please use std.datetime instead.)
6 | *
7 | * dateparse module.
8 | *
9 | * Copyright: Copyright Digital Mars 2000 - 2009.
10 | * License: Boost License 1.0.
11 | * Authors: $(WEB digitalmars.com, Walter Bright)
12 | * Source: $(PHOBOSSRC std/_dateparse.d)
13 | */
14 | /*
15 | * Copyright Digital Mars 2000 - 2009.
16 | * Distributed under the Boost Software License, Version 1.0.
17 | * (See accompanying file LICENSE_1_0.txt or copy at
18 | * http://www.boost.org/LICENSE_1_0.txt)
19 | */
20 | module undead.dateparse;
21 |
22 | private
23 | {
24 | import std.algorithm, std.string;
25 | import core.stdc.stdlib;
26 | import undead.date;
27 | }
28 |
29 | //deprecated:
30 |
31 | //debug=dateparse;
32 |
33 | class DateParseError : Error
34 | {
35 | this(string s)
36 | {
37 | super("Invalid date string: " ~ s);
38 | }
39 | }
40 |
41 | struct DateParse
42 | {
43 | void parse(string s, out Date date)
44 | {
45 | this = DateParse.init;
46 |
47 | //version (Win32)
48 | buffer = (cast(char *)alloca(s.length))[0 .. s.length];
49 | //else
50 | //buffer = new char[s.length];
51 |
52 | debug(dateparse) printf("DateParse.parse('%.*s')\n", s);
53 | if (!parseString(s))
54 | {
55 | goto Lerror;
56 | }
57 |
58 | /+
59 | if (year == year.init)
60 | year = 0;
61 | else
62 | +/
63 | debug(dateparse)
64 | printf("year = %d, month = %d, day = %d\n%02d:%02d:%02d.%03d\nweekday = %d, tzcorrection = %d\n",
65 | year, month, day,
66 | hours, minutes, seconds, ms,
67 | weekday, tzcorrection);
68 | if (
69 | year == year.init ||
70 | (month < 1 || month > 12) ||
71 | (day < 1 || day > 31) ||
72 | (hours < 0 || hours > 23) ||
73 | (minutes < 0 || minutes > 59) ||
74 | (seconds < 0 || seconds > 59) ||
75 | (tzcorrection != int.min &&
76 | ((tzcorrection < -2300 || tzcorrection > 2300) ||
77 | (tzcorrection % 10)))
78 | )
79 | {
80 | Lerror:
81 | throw new DateParseError(s);
82 | }
83 |
84 | if (ampm)
85 | { if (hours > 12)
86 | goto Lerror;
87 | if (hours < 12)
88 | {
89 | if (ampm == 2) // if P.M.
90 | hours += 12;
91 | }
92 | else if (ampm == 1) // if 12am
93 | {
94 | hours = 0; // which is midnight
95 | }
96 | }
97 |
98 | // if (tzcorrection != tzcorrection.init)
99 | // tzcorrection /= 100;
100 |
101 | if (year >= 0 && year <= 99)
102 | year += 1900;
103 |
104 | date.year = year;
105 | date.month = month;
106 | date.day = day;
107 | date.hour = hours;
108 | date.minute = minutes;
109 | date.second = seconds;
110 | date.ms = ms;
111 | date.weekday = weekday;
112 | date.tzcorrection = tzcorrection;
113 | }
114 |
115 |
116 | private:
117 | int year = int.min; // our "nan" Date value
118 | int month; // 1..12
119 | int day; // 1..31
120 | int hours; // 0..23
121 | int minutes; // 0..59
122 | int seconds; // 0..59
123 | int ms; // 0..999
124 | int weekday; // 1..7
125 | int ampm; // 0: not specified
126 | // 1: AM
127 | // 2: PM
128 | int tzcorrection = int.min; // -1200..1200 correction in hours
129 |
130 | string s;
131 | int si;
132 | int number;
133 | char[] buffer;
134 |
135 | enum DP : byte
136 | {
137 | err,
138 | weekday,
139 | month,
140 | number,
141 | end,
142 | colon,
143 | minus,
144 | slash,
145 | ampm,
146 | plus,
147 | tz,
148 | dst,
149 | dsttz,
150 | }
151 |
152 | DP nextToken()
153 | { int nest;
154 | uint c;
155 | int bi;
156 | DP result = DP.err;
157 |
158 | //printf("DateParse::nextToken()\n");
159 | for (;;)
160 | {
161 | assert(si <= s.length);
162 | if (si == s.length)
163 | { result = DP.end;
164 | goto Lret;
165 | }
166 | //printf("\ts[%d] = '%c'\n", si, s[si]);
167 | switch (s[si])
168 | {
169 | case ':': result = DP.colon; goto ret_inc;
170 | case '+': result = DP.plus; goto ret_inc;
171 | case '-': result = DP.minus; goto ret_inc;
172 | case '/': result = DP.slash; goto ret_inc;
173 | case '.':
174 | version(DATE_DOT_DELIM)
175 | {
176 | result = DP.slash;
177 | goto ret_inc;
178 | }
179 | else
180 | {
181 | si++;
182 | break;
183 | }
184 |
185 | ret_inc:
186 | si++;
187 | goto Lret;
188 |
189 | case ' ':
190 | case '\n':
191 | case '\r':
192 | case '\t':
193 | case ',':
194 | si++;
195 | break;
196 |
197 | case '(': // comment
198 | nest = 1;
199 | for (;;)
200 | {
201 | si++;
202 | if (si == s.length)
203 | goto Lret; // error
204 | switch (s[si])
205 | {
206 | case '(':
207 | nest++;
208 | break;
209 |
210 | case ')':
211 | if (--nest == 0)
212 | goto Lendofcomment;
213 | break;
214 |
215 | default:
216 | break;
217 | }
218 | }
219 | Lendofcomment:
220 | si++;
221 | break;
222 |
223 | default:
224 | number = 0;
225 | for (;;)
226 | {
227 | if (si == s.length)
228 | // c cannot be undefined here
229 | break;
230 | c = s[si];
231 | if (!(c >= '0' && c <= '9'))
232 | break;
233 | result = DP.number;
234 | number = number * 10 + (c - '0');
235 | si++;
236 | }
237 | if (result == DP.number)
238 | goto Lret;
239 |
240 | bi = 0;
241 | bufloop:
242 | while (c >= 'a' && c <= 'z' || c >= 'A' && c <= 'Z')
243 | {
244 | if (c < 'a') // if upper case
245 | c += cast(uint)'a' - cast(uint)'A'; // to lower case
246 | buffer[bi] = cast(char)c;
247 | bi++;
248 | do
249 | {
250 | si++;
251 | if (si == s.length)
252 | break bufloop;
253 | c = s[si];
254 | } while (c == '.'); // ignore embedded '.'s
255 | }
256 | result = classify(buffer[0 .. bi].idup);
257 | goto Lret;
258 | }
259 | }
260 | Lret:
261 | //printf("-DateParse::nextToken()\n");
262 | return result;
263 | }
264 |
265 | DP classify(string buf)
266 | {
267 | struct DateID
268 | {
269 | string name;
270 | DP tok;
271 | short value;
272 | }
273 |
274 | static immutable DateID[] dateidtab =
275 | [
276 | { "january", DP.month, 1},
277 | { "february", DP.month, 2},
278 | { "march", DP.month, 3},
279 | { "april", DP.month, 4},
280 | { "may", DP.month, 5},
281 | { "june", DP.month, 6},
282 | { "july", DP.month, 7},
283 | { "august", DP.month, 8},
284 | { "september", DP.month, 9},
285 | { "october", DP.month, 10},
286 | { "november", DP.month, 11},
287 | { "december", DP.month, 12},
288 | { "jan", DP.month, 1},
289 | { "feb", DP.month, 2},
290 | { "mar", DP.month, 3},
291 | { "apr", DP.month, 4},
292 | { "jun", DP.month, 6},
293 | { "jul", DP.month, 7},
294 | { "aug", DP.month, 8},
295 | { "sep", DP.month, 9},
296 | { "sept", DP.month, 9},
297 | { "oct", DP.month, 10},
298 | { "nov", DP.month, 11},
299 | { "dec", DP.month, 12},
300 |
301 | { "sunday", DP.weekday, 1},
302 | { "monday", DP.weekday, 2},
303 | { "tuesday", DP.weekday, 3},
304 | { "tues", DP.weekday, 3},
305 | { "wednesday", DP.weekday, 4},
306 | { "wednes", DP.weekday, 4},
307 | { "thursday", DP.weekday, 5},
308 | { "thur", DP.weekday, 5},
309 | { "thurs", DP.weekday, 5},
310 | { "friday", DP.weekday, 6},
311 | { "saturday", DP.weekday, 7},
312 |
313 | { "sun", DP.weekday, 1},
314 | { "mon", DP.weekday, 2},
315 | { "tue", DP.weekday, 3},
316 | { "wed", DP.weekday, 4},
317 | { "thu", DP.weekday, 5},
318 | { "fri", DP.weekday, 6},
319 | { "sat", DP.weekday, 7},
320 |
321 | { "am", DP.ampm, 1},
322 | { "pm", DP.ampm, 2},
323 |
324 | { "gmt", DP.tz, +000},
325 | { "ut", DP.tz, +000},
326 | { "utc", DP.tz, +000},
327 | { "wet", DP.tz, +000},
328 | { "z", DP.tz, +000},
329 | { "wat", DP.tz, +100},
330 | { "a", DP.tz, +100},
331 | { "at", DP.tz, +200},
332 | { "b", DP.tz, +200},
333 | { "c", DP.tz, +300},
334 | { "ast", DP.tz, +400},
335 | { "d", DP.tz, +400},
336 | { "est", DP.tz, +500},
337 | { "e", DP.tz, +500},
338 | { "cst", DP.tz, +600},
339 | { "f", DP.tz, +600},
340 | { "mst", DP.tz, +700},
341 | { "g", DP.tz, +700},
342 | { "pst", DP.tz, +800},
343 | { "h", DP.tz, +800},
344 | { "yst", DP.tz, +900},
345 | { "i", DP.tz, +900},
346 | { "ahst", DP.tz, +1000},
347 | { "cat", DP.tz, +1000},
348 | { "hst", DP.tz, +1000},
349 | { "k", DP.tz, +1000},
350 | { "nt", DP.tz, +1100},
351 | { "l", DP.tz, +1100},
352 | { "idlw", DP.tz, +1200},
353 | { "m", DP.tz, +1200},
354 |
355 | { "cet", DP.tz, -100},
356 | { "fwt", DP.tz, -100},
357 | { "met", DP.tz, -100},
358 | { "mewt", DP.tz, -100},
359 | { "swt", DP.tz, -100},
360 | { "n", DP.tz, -100},
361 | { "eet", DP.tz, -200},
362 | { "o", DP.tz, -200},
363 | { "bt", DP.tz, -300},
364 | { "p", DP.tz, -300},
365 | { "zp4", DP.tz, -400},
366 | { "q", DP.tz, -400},
367 | { "zp5", DP.tz, -500},
368 | { "r", DP.tz, -500},
369 | { "zp6", DP.tz, -600},
370 | { "s", DP.tz, -600},
371 | { "wast", DP.tz, -700},
372 | { "t", DP.tz, -700},
373 | { "cct", DP.tz, -800},
374 | { "u", DP.tz, -800},
375 | { "jst", DP.tz, -900},
376 | { "v", DP.tz, -900},
377 | { "east", DP.tz, -1000},
378 | { "gst", DP.tz, -1000},
379 | { "w", DP.tz, -1000},
380 | { "x", DP.tz, -1100},
381 | { "idle", DP.tz, -1200},
382 | { "nzst", DP.tz, -1200},
383 | { "nzt", DP.tz, -1200},
384 | { "y", DP.tz, -1200},
385 |
386 | { "bst", DP.dsttz, 000},
387 | { "adt", DP.dsttz, +400},
388 | { "edt", DP.dsttz, +500},
389 | { "cdt", DP.dsttz, +600},
390 | { "mdt", DP.dsttz, +700},
391 | { "pdt", DP.dsttz, +800},
392 | { "ydt", DP.dsttz, +900},
393 | { "hdt", DP.dsttz, +1000},
394 | { "mest", DP.dsttz, -100},
395 | { "mesz", DP.dsttz, -100},
396 | { "sst", DP.dsttz, -100},
397 | { "fst", DP.dsttz, -100},
398 | { "wadt", DP.dsttz, -700},
399 | { "eadt", DP.dsttz, -1000},
400 | { "nzdt", DP.dsttz, -1200},
401 |
402 | { "dst", DP.dst, 0},
403 | ];
404 |
405 | //message(DTEXT("DateParse::classify('%s')\n"), buf);
406 |
407 | // Do a linear search. Yes, it would be faster with a binary
408 | // one.
409 | for (uint i = 0; i < dateidtab.length; i++)
410 | {
411 | if (cmp(dateidtab[i].name, buf) == 0)
412 | {
413 | number = dateidtab[i].value;
414 | return dateidtab[i].tok;
415 | }
416 | }
417 | return DP.err;
418 | }
419 |
420 | int parseString(string s)
421 | {
422 | int n1;
423 | int dp;
424 | int sisave;
425 | int result;
426 |
427 | //message(DTEXT("DateParse::parseString('%ls')\n"), s);
428 | this.s = s;
429 | si = 0;
430 | dp = nextToken();
431 | for (;;)
432 | {
433 | //message(DTEXT("\tdp = %d\n"), dp);
434 | switch (dp)
435 | {
436 | case DP.end:
437 | result = 1;
438 | Lret:
439 | return result;
440 |
441 | case DP.err:
442 | case_error:
443 | //message(DTEXT("\terror\n"));
444 | default:
445 | result = 0;
446 | goto Lret;
447 |
448 | case DP.minus:
449 | break; // ignore spurious '-'
450 |
451 | case DP.weekday:
452 | weekday = number;
453 | break;
454 |
455 | case DP.month: // month day, [year]
456 | month = number;
457 | dp = nextToken();
458 | if (dp == DP.number)
459 | {
460 | day = number;
461 | sisave = si;
462 | dp = nextToken();
463 | if (dp == DP.number)
464 | {
465 | n1 = number;
466 | dp = nextToken();
467 | if (dp == DP.colon)
468 | { // back up, not a year
469 | si = sisave;
470 | }
471 | else
472 | { year = n1;
473 | continue;
474 | }
475 | break;
476 | }
477 | }
478 | continue;
479 |
480 | case DP.number:
481 | n1 = number;
482 | dp = nextToken();
483 | switch (dp)
484 | {
485 | case DP.end:
486 | year = n1;
487 | break;
488 |
489 | case DP.minus:
490 | case DP.slash: // n1/ ? ? ?
491 | dp = parseCalendarDate(n1);
492 | if (dp == DP.err)
493 | goto case_error;
494 | break;
495 |
496 | case DP.colon: // hh:mm [:ss] [am | pm]
497 | dp = parseTimeOfDay(n1);
498 | if (dp == DP.err)
499 | goto case_error;
500 | break;
501 |
502 | case DP.ampm:
503 | hours = n1;
504 | minutes = 0;
505 | seconds = 0;
506 | ampm = number;
507 | break;
508 |
509 | case DP.month:
510 | day = n1;
511 | month = number;
512 | dp = nextToken();
513 | if (dp == DP.number)
514 | { // day month year
515 | year = number;
516 | dp = nextToken();
517 | }
518 | break;
519 |
520 | default:
521 | year = n1;
522 | break;
523 | }
524 | continue;
525 | }
526 | dp = nextToken();
527 | }
528 | // @@@ bug in the compiler: this is never reachable
529 | assert(0);
530 | }
531 |
532 | int parseCalendarDate(int n1)
533 | {
534 | int n2;
535 | int n3;
536 | int dp;
537 |
538 | debug(dateparse) printf("DateParse.parseCalendarDate(%d)\n", n1);
539 | dp = nextToken();
540 | if (dp == DP.month) // day/month
541 | {
542 | day = n1;
543 | month = number;
544 | dp = nextToken();
545 | if (dp == DP.number)
546 | { // day/month year
547 | year = number;
548 | dp = nextToken();
549 | }
550 | else if (dp == DP.minus || dp == DP.slash)
551 | { // day/month/year
552 | dp = nextToken();
553 | if (dp != DP.number)
554 | goto case_error;
555 | year = number;
556 | dp = nextToken();
557 | }
558 | return dp;
559 | }
560 | if (dp != DP.number)
561 | goto case_error;
562 | n2 = number;
563 | //message(DTEXT("\tn2 = %d\n"), n2);
564 | dp = nextToken();
565 | if (dp == DP.minus || dp == DP.slash)
566 | {
567 | dp = nextToken();
568 | if (dp != DP.number)
569 | goto case_error;
570 | n3 = number;
571 | //message(DTEXT("\tn3 = %d\n"), n3);
572 | dp = nextToken();
573 |
574 | // case1: year/month/day
575 | // case2: month/day/year
576 | int case1, case2;
577 |
578 | case1 = (n1 > 12 ||
579 | (n2 >= 1 && n2 <= 12) &&
580 | (n3 >= 1 && n3 <= 31));
581 | case2 = ((n1 >= 1 && n1 <= 12) &&
582 | (n2 >= 1 && n2 <= 31) ||
583 | n3 > 31);
584 | if (case1 == case2)
585 | goto case_error;
586 | if (case1)
587 | {
588 | year = n1;
589 | month = n2;
590 | day = n3;
591 | }
592 | else
593 | {
594 | month = n1;
595 | day = n2;
596 | year = n3;
597 | }
598 | }
599 | else
600 | { // must be month/day
601 | month = n1;
602 | day = n2;
603 | }
604 | return dp;
605 |
606 | case_error:
607 | return DP.err;
608 | }
609 |
610 | int parseTimeOfDay(int n1)
611 | {
612 | int dp;
613 | int sign;
614 |
615 | // 12am is midnight
616 | // 12pm is noon
617 |
618 | //message(DTEXT("DateParse::parseTimeOfDay(%d)\n"), n1);
619 | hours = n1;
620 | dp = nextToken();
621 | if (dp != DP.number)
622 | goto case_error;
623 | minutes = number;
624 | dp = nextToken();
625 | if (dp == DP.colon)
626 | {
627 | dp = nextToken();
628 | if (dp != DP.number)
629 | goto case_error;
630 | seconds = number;
631 | dp = nextToken();
632 | }
633 | else
634 | seconds = 0;
635 |
636 | if (dp == DP.ampm)
637 | {
638 | ampm = number;
639 | dp = nextToken();
640 | }
641 | else if (dp == DP.plus || dp == DP.minus)
642 | {
643 | Loffset:
644 | sign = (dp == DP.minus) ? -1 : 1;
645 | dp = nextToken();
646 | if (dp != DP.number)
647 | goto case_error;
648 | tzcorrection = -sign * number;
649 | dp = nextToken();
650 | }
651 | else if (dp == DP.tz)
652 | {
653 | tzcorrection = number;
654 | dp = nextToken();
655 | if (number == 0 && (dp == DP.plus || dp == DP.minus))
656 | goto Loffset;
657 | if (dp == DP.dst)
658 | { tzcorrection += 100;
659 | dp = nextToken();
660 | }
661 | }
662 | else if (dp == DP.dsttz)
663 | {
664 | tzcorrection = number;
665 | dp = nextToken();
666 | }
667 |
668 | return dp;
669 |
670 | case_error:
671 | return DP.err;
672 | }
673 |
674 | }
675 |
676 | unittest
677 | {
678 | DateParse dp;
679 | Date d;
680 |
681 | dp.parse("March 10, 1959 12:00 -800", d);
682 | assert(d.year == 1959);
683 | assert(d.month == 3);
684 | assert(d.day == 10);
685 | assert(d.hour == 12);
686 | assert(d.minute == 0);
687 | assert(d.second == 0);
688 | assert(d.ms == 0);
689 | assert(d.weekday == 0);
690 | assert(d.tzcorrection == 800);
691 |
692 | dp.parse("Tue Apr 02 02:04:57 GMT-0800 1996", d);
693 | assert(d.year == 1996);
694 | assert(d.month == 4);
695 | assert(d.day == 2);
696 | assert(d.hour == 2);
697 | assert(d.minute == 4);
698 | assert(d.second == 57);
699 | assert(d.ms == 0);
700 | assert(d.weekday == 3);
701 | assert(d.tzcorrection == 800);
702 |
703 | dp.parse("March 14, -1980 21:14:50", d);
704 | assert(d.year == 1980);
705 | assert(d.month == 3);
706 | assert(d.day == 14);
707 | assert(d.hour == 21);
708 | assert(d.minute == 14);
709 | assert(d.second == 50);
710 | assert(d.ms == 0);
711 | assert(d.weekday == 0);
712 | assert(d.tzcorrection == int.min);
713 |
714 | dp.parse("Tue Apr 02 02:04:57 1996", d);
715 | assert(d.year == 1996);
716 | assert(d.month == 4);
717 | assert(d.day == 2);
718 | assert(d.hour == 2);
719 | assert(d.minute == 4);
720 | assert(d.second == 57);
721 | assert(d.ms == 0);
722 | assert(d.weekday == 3);
723 | assert(d.tzcorrection == int.min);
724 |
725 | dp.parse("Tue, 02 Apr 1996 02:04:57 G.M.T.", d);
726 | assert(d.year == 1996);
727 | assert(d.month == 4);
728 | assert(d.day == 2);
729 | assert(d.hour == 2);
730 | assert(d.minute == 4);
731 | assert(d.second == 57);
732 | assert(d.ms == 0);
733 | assert(d.weekday == 3);
734 | assert(d.tzcorrection == 0);
735 |
736 | dp.parse("December 31, 3000", d);
737 | assert(d.year == 3000);
738 | assert(d.month == 12);
739 | assert(d.day == 31);
740 | assert(d.hour == 0);
741 | assert(d.minute == 0);
742 | assert(d.second == 0);
743 | assert(d.ms == 0);
744 | assert(d.weekday == 0);
745 | assert(d.tzcorrection == int.min);
746 |
747 | dp.parse("Wed, 31 Dec 1969 16:00:00 GMT", d);
748 | assert(d.year == 1969);
749 | assert(d.month == 12);
750 | assert(d.day == 31);
751 | assert(d.hour == 16);
752 | assert(d.minute == 0);
753 | assert(d.second == 0);
754 | assert(d.ms == 0);
755 | assert(d.weekday == 4);
756 | assert(d.tzcorrection == 0);
757 |
758 | dp.parse("1/1/1999 12:30 AM", d);
759 | assert(d.year == 1999);
760 | assert(d.month == 1);
761 | assert(d.day == 1);
762 | assert(d.hour == 0);
763 | assert(d.minute == 30);
764 | assert(d.second == 0);
765 | assert(d.ms == 0);
766 | assert(d.weekday == 0);
767 | assert(d.tzcorrection == int.min);
768 |
769 | dp.parse("Tue, 20 May 2003 15:38:58 +0530", d);
770 | assert(d.year == 2003);
771 | assert(d.month == 5);
772 | assert(d.day == 20);
773 | assert(d.hour == 15);
774 | assert(d.minute == 38);
775 | assert(d.second == 58);
776 | assert(d.ms == 0);
777 | assert(d.weekday == 3);
778 | assert(d.tzcorrection == -530);
779 |
780 | debug(dateparse) printf("year = %d, month = %d, day = %d\n%02d:%02d:%02d.%03d\nweekday = %d, tzcorrection = %d\n",
781 | d.year, d.month, d.day,
782 | d.hour, d.minute, d.second, d.ms,
783 | d.weekday, d.tzcorrection);
784 | }
785 |
--------------------------------------------------------------------------------
/dmdsamples/dhry.d:
--------------------------------------------------------------------------------
1 |
2 | /*
3 | *************************************************************************
4 | *
5 | * "DHRYSTONE" Benchmark Program
6 | * -----------------------------
7 | *
8 | * Version: C, Version 2.1
9 | *
10 | * File: dhry.h (part 1 of 3)
11 | *
12 | * Date: May 25, 1988
13 | *
14 | * Author: Reinhold P. Weicker
15 | * Siemens Nixdorf Inf. Syst.
16 | * STM OS 32
17 | * Otto-Hahn-Ring 6
18 | * W-8000 Muenchen 83
19 | * Germany
20 | * Phone: [+49]-89-636-42436
21 | * (8-17 Central European Time)
22 | * UUCP: weicker@ztivax.uucp@unido.uucp
23 | * Internet: weicker@ztivax.siemens.com
24 | *
25 | * Original Version (in Ada) published in
26 | * "Communications of the ACM" vol. 27., no. 10 (Oct. 1984),
27 | * pp. 1013 - 1030, together with the statistics
28 | * on which the distribution of statements etc. is based.
29 | *
30 | * In this C version, the following C library functions are
31 | * used:
32 | * - strcpy, strcmp (inside the measurement loop)
33 | * - printf, scanf (outside the measurement loop)
34 | *
35 | * Collection of Results:
36 | * Reinhold Weicker (address see above) and
37 | *
38 | * Rick Richardson
39 | * PC Research. Inc.
40 | * 94 Apple Orchard Drive
41 | * Tinton Falls, NJ 07724
42 | * Phone: (201) 834-1378 (9-17 EST)
43 | * UUCP: ...!uunet!pcrat!rick
44 | *
45 | * Please send results to Rick Richardson and/or Reinhold Weicker.
46 | * Complete information should be given on hardware and software
47 | * used. Hardware information includes: Machine type, CPU, type and
48 | * size of caches; for microprocessors: clock frequency, memory speed
49 | * (number of wait states). Software information includes: Compiler
50 | * (and runtime library) manufacturer and version, compilation
51 | * switches, OS version. The Operating System version may give an
52 | * indication about the compiler; Dhrystone itself performs no OS
53 | * calls in the measurement loop.
54 | *
55 | * The complete output generated by the program should be mailed
56 | * such that at least some checks for correctness can be made.
57 | *
58 | *************************************************************************
59 | *
60 | * History: This version C/2.1 has been made for two reasons:
61 | *
62 | * 1) There is an obvious need for a common C version of
63 | * Dhrystone, since C is at present the most popular system
64 | * programming language for the class of processors
65 | * (microcomputers, minicomputers) where Dhrystone is used
66 | * most. There should be, as far as possible, only one C
67 | * version of Dhrystone such that results can be compared
68 | * without restrictions. In the past, the C versions
69 | * distributed by Rick Richardson (Version 1.1) and by
70 | * Reinhold Weicker had small (though not significant)
71 | * differences.
72 | *
73 | * 2) As far as it is possible without changes to the
74 | * Dhrystone statistics, optimizing compilers should be
75 | * prevented from removing significant statements.
76 | *
77 | * This C version has been developed in cooperation with
78 | * Rick Richardson (Tinton Falls, NJ), it incorporates many
79 | * ideas from the "Version 1.1" distributed previously by
80 | * him over the UNIX network Usenet.
81 | * I also thank Chaim Benedelac (National Semiconductor),
82 | * David Ditzel (SUN), Earl Killian and John Mashey (MIPS),
83 | * Alan Smith and Rafael Saavedra-Barrera (UC at Berkeley)
84 | * for their help with comments on earlier versions of the
85 | * benchmark.
86 | *
87 | * Changes: In the initialization part, this version follows mostly
88 | * Rick Richardson's version distributed via Usenet, not the
89 | * version distributed earlier via floppy disk by Reinhold
90 | * Weicker. As a concession to older compilers, names have
91 | * been made unique within the first 8 characters. Inside the
92 | * measurement loop, this version follows the version
93 | * previously distributed by Reinhold Weicker.
94 | *
95 | * At several places in the benchmark, code has been added,
96 | * but within the measurement loop only in branches that
97 | * are not executed. The intention is that optimizing
98 | * compilers should be prevented from moving code out of the
99 | * measurement loop, or from removing code altogether. Since
100 | * the statements that are executed within the measurement
101 | * loop have NOT been changed, the numbers defining the
102 | * "Dhrystone distribution" (distribution of statements,
103 | * operand types and locality) still hold. Except for
104 | * sophisticated optimizing compilers, execution times for
105 | * this version should be the same as for previous versions.
106 | *
107 | * Since it has proven difficult to subtract the time for the
108 | * measurement loop overhead in a correct way, the loop check
109 | * has been made a part of the benchmark. This does have
110 | * an impact - though a very minor one - on the distribution
111 | * statistics which have been updated for this version.
112 | *
113 | * All changes within the measurement loop are described
114 | * and discussed in the companion paper "Rationale for
115 | * Dhrystone version 2".
116 | *
117 | * Because of the self-imposed limitation that the order and
118 | * distribution of the executed statements should not be
119 | * changed, there are still cases where optimizing compilers
120 | * may not generate code for some statements. To a certain
121 | * degree, this is unavoidable for small synthetic
122 | * benchmarks. Users of the benchmark are advised to check
123 | * code listings whether code is generated for all statements
124 | * of Dhrystone.
125 | *
126 | * Version 2.1 is identical to version 2.0 distributed via
127 | * the UNIX network Usenet in March 1988 except that it
128 | * corrects some minor deficiencies that were found by users
129 | * of version 2.0. The only change within the measurement
130 | * loop is that a non-executed "else" part was added to the
131 | * "if" statement in Func_3, and a non-executed "else" part
132 | * removed from Proc_3.
133 | *
134 | *************************************************************************
135 | *
136 | * Defines: The following "Defines" are possible:
137 | * -DROPT (default: Not defined)
138 | * As an approximation to what an average C
139 | * programmer might do, the "register" storage class
140 | * is applied (if enabled by -DROPT)
141 | * - for local variables, if they are used
142 | * (dynamically) five or more times
143 | * - for parameters if they are used (dynamically)
144 | * six or more times
145 | * Note that an optimal "register" strategy is
146 | * compiler-dependent, and that "register"
147 | * declarations do not necessarily lead to faster
148 | * execution.
149 | * -DNOSTRUCTASSIGN (default: Not defined)
150 | * Define if the C compiler does not support
151 | * assignment of structures.
152 | * -DNOENUMS (default: Not defined)
153 | * Define if the C compiler does not support
154 | * enumeration types.
155 | *
156 | *************************************************************************
157 | *
158 | * Compilation model and measurement (IMPORTANT):
159 | *
160 | * This C version of Dhrystone consists of three files:
161 | * - dhry.h (this file, containing global definitions and comments)
162 | * - dhry_1.c (containing the code corresponding to Ada package Pack_1)
163 | * - dhry_2.c (containing the code corresponding to Ada package Pack_2)
164 | *
165 | * The following "ground rules" apply for measurements:
166 | * - Separate compilation
167 | * - No procedure merging
168 | * - Otherwise, compiler optimizations are allowed but should be
169 | * indicated
170 | * - Default results are those without register declarations
171 | * See the companion paper "Rationale for Dhrystone Version 2" for a more
172 | * detailed discussion of these ground rules.
173 | *
174 | * For 16-Bit processors (e.g. 80186, 80286), times for all compilation
175 | * models ("small", "medium", "large" etc.) should be given if possible,
176 | * together with a definition of these models for the compiler system
177 | * used.
178 | *
179 | *************************************************************************
180 | *
181 | * Dhrystone (C version) statistics:
182 | *
183 | * [Comment from the first distribution, updated for version 2.
184 | * Note that because of language differences, the numbers are slightly
185 | * different from the Ada version.]
186 | *
187 | * The following program contains statements of a high level programming
188 | * language (here: C) in a distribution considered representative:
189 | *
190 | * assignments 52 (51.0 %)
191 | * control statements 33 (32.4 %)
192 | * procedure, function calls 17 (16.7 %)
193 | *
194 | * 103 statements are dynamically executed. The program is balanced with
195 | * respect to the three aspects:
196 | *
197 | * - statement type
198 | * - operand type
199 | * - operand locality
200 | * operand global, local, parameter, or constant.
201 | *
202 | * The combination of these three aspects is balanced only approximately.
203 | *
204 | * 1. Statement Type:
205 | * ----------------- number
206 | *
207 | * V1 = V2 9
208 | * (incl. V1 = F(..)
209 | * V = Constant 12
210 | * Assignment, 7
211 | * with array element
212 | * Assignment, 6
213 | * with record component
214 | * --
215 | * 34 34
216 | *
217 | * X = Y +|-|"&&"|"|" Z 5
218 | * X = Y +|-|"==" Constant 6
219 | * X = X +|- 1 3
220 | * X = Y *|/ Z 2
221 | * X = Expression, 1
222 | * two operators
223 | * X = Expression, 1
224 | * three operators
225 | * --
226 | * 18 18
227 | *
228 | * if .... 14
229 | * with "else" 7
230 | * without "else" 7
231 | * executed 3
232 | * not executed 4
233 | * for ... 7 | counted every time
234 | * while ... 4 | the loop condition
235 | * do ... while 1 | is evaluated
236 | * switch ... 1
237 | * break 1
238 | * declaration with 1
239 | * initialization
240 | * --
241 | * 34 34
242 | *
243 | * P (...) procedure call 11
244 | * user procedure 10
245 | * library procedure 1
246 | * X = F (...)
247 | * function call 6
248 | * user function 5
249 | * library function 1
250 | * --
251 | * 17 17
252 | * ---
253 | * 103
254 | *
255 | * The average number of parameters in procedure or function calls
256 | * is 1.82 (not counting the function values as implicit parameters).
257 | *
258 | *
259 | * 2. Operators
260 | * ------------
261 | * number approximate
262 | * percentage
263 | *
264 | * Arithmetic 32 50.8
265 | *
266 | * + 21 33.3
267 | * - 7 11.1
268 | * * 3 4.8
269 | * / (int div) 1 1.6
270 | *
271 | * Comparison 27 42.8
272 | *
273 | * == 9 14.3
274 | * /= 4 6.3
275 | * > 1 1.6
276 | * < 3 4.8
277 | * >= 1 1.6
278 | * <= 9 14.3
279 | *
280 | * Logic 4 6.3
281 | *
282 | * && (AND-THEN) 1 1.6
283 | * | (OR) 1 1.6
284 | * ! (NOT) 2 3.2
285 | *
286 | * -- -----
287 | * 63 100.1
288 | *
289 | *
290 | * 3. Operand Type (counted once per operand reference):
291 | * ---------------
292 | * number approximate
293 | * percentage
294 | *
295 | * Integer 175 72.3 %
296 | * Character 45 18.6 %
297 | * Pointer 12 5.0 %
298 | * String30 6 2.5 %
299 | * Array 2 0.8 %
300 | * Record 2 0.8 %
301 | * --- -------
302 | * 242 100.0 %
303 | *
304 | * When there is an access path leading to the final operand (e.g. a
305 | * record component), only the final data type on the access path is
306 | * counted.
307 | *
308 | *
309 | * 4. Operand Locality:
310 | * -------------------
311 | * number approximate
312 | * percentage
313 | *
314 | * local variable 114 47.1 %
315 | * global variable 22 9.1 %
316 | * parameter 45 18.6 %
317 | * value 23 9.5 %
318 | * reference 22 9.1 %
319 | * function result 6 2.5 %
320 | * constant 55 22.7 %
321 | * --- -------
322 | * 242 100.0 %
323 | *
324 | *
325 | * The program does not compute anything meaningful, but it is
326 | * syntactically and semantically correct. All variables have a value
327 | * assigned to them before they are used as a source operand.
328 | *
329 | * There has been no explicit effort to account for the effects of a
330 | * cache, or to balance the use of long or short displacements for code
331 | * or data.
332 | *
333 | *************************************************************************
334 | */
335 |
336 | import core.stdc.stdio;
337 | import core.stdc.string;
338 | import core.stdc.stdlib;
339 | import std.string;
340 |
341 | /* Compiler and system dependent definitions: */
342 |
343 | const double Mic_secs_Per_Second = 1000000.0;
344 |
345 | /* Berkeley UNIX C returns process times in seconds/HZ */
346 |
347 | enum { Ident_1, Ident_2, Ident_3, Ident_4, Ident_5 }
348 | alias int Enumeration;
349 |
350 | /* for boolean and enumeration types in Ada, Pascal */
351 |
352 | /* General definitions: */
353 |
354 | const int StrLen = 30;
355 |
356 | alias int One_Thirty;
357 | alias int One_Fifty;
358 | alias char Capital_Letter;
359 | alias bool Boolean;
360 | alias char[StrLen] Str_30;
361 | alias int[50] Arr_1_Dim;
362 | alias int[50][50] Arr_2_Dim;
363 |
364 | struct record
365 | {
366 | record *Ptr_Comp;
367 | Enumeration Discr;
368 | union V
369 | {
370 | struct V1
371 | {
372 | Enumeration Enum_Comp;
373 | int Int_Comp;
374 | char[StrLen] Str_Comp;
375 | }
376 | V1 var_1;
377 | struct V2
378 | {
379 | Enumeration E_Comp_2;
380 | char[StrLen] Str_2_Comp;
381 | }
382 | V2 var_2;
383 | struct V3
384 | {
385 | char Ch_1_Comp;
386 | char Ch_2_Comp;
387 | }
388 | V3 var_3;
389 | }
390 | V variant;
391 | }
392 |
393 | alias record Rec_Type;
394 | alias record *Rec_Pointer;
395 |
396 | /* Global Variables: */
397 |
398 | Rec_Pointer Ptr_Glob,
399 | Next_Ptr_Glob;
400 | int Int_Glob;
401 | Boolean Bool_Glob;
402 | char Ch_1_Glob,
403 | Ch_2_Glob;
404 | int[50] Arr_1_Glob;
405 | int[50][50] Arr_2_Glob;
406 |
407 | char[StrLen] Reg_Define = "Register option selected.";
408 |
409 | /* variables for time measurement: */
410 |
411 | const int Too_Small_Time = 2;
412 |
413 | /* Measurements should last at least 2 seconds */
414 |
415 | double Begin_Time,
416 | End_Time,
417 | User_Time;
418 |
419 | double Microseconds,
420 | Dhrystones_Per_Second,
421 | Vax_Mips;
422 |
423 | /* end of variables for time measurement */
424 | void main()
425 |
426 | /*****/
427 |
428 | /* main program, corresponds to procedures */
429 | /* Main and Proc_0 in the Ada version */
430 | {
431 | One_Fifty Int_1_Loc;
432 | One_Fifty Int_2_Loc;
433 | One_Fifty Int_3_Loc;
434 | char Ch_Index;
435 | Enumeration Enum_Loc;
436 | Str_30 Str_1_Loc;
437 | Str_30 Str_2_Loc;
438 | int Run_Index;
439 | int Number_Of_Runs;
440 |
441 | FILE *Ap;
442 |
443 | /* Initializations */
444 |
445 | if ((Ap = fopen("dhry.res", "a+")) == null)
446 | {
447 | printf("Can not open dhry.res\n\n");
448 | exit(1);
449 | }
450 |
451 | Next_Ptr_Glob = cast(Rec_Pointer) malloc (Rec_Type.sizeof);
452 | Ptr_Glob = cast(Rec_Pointer) malloc (Rec_Type.sizeof);
453 |
454 | Ptr_Glob.Ptr_Comp = Next_Ptr_Glob;
455 | Ptr_Glob.Discr = Ident_1;
456 | Ptr_Glob.variant.var_1.Enum_Comp = Ident_3;
457 | Ptr_Glob.variant.var_1.Int_Comp = 40;
458 |
459 | // strcpy (Ptr_Glob.variant.var_1.Str_Comp,
460 | // "DHRYSTONE PROGRAM, SOME STRING");
461 | // strcpy (Str_1_Loc, "DHRYSTONE PROGRAM, 1'ST STRING");
462 | Ptr_Glob.variant.var_1.Str_Comp[] = "DHRYSTONE PROGRAM, SOME STRING";
463 | Str_1_Loc[] = "DHRYSTONE PROGRAM, 1'ST STRING";
464 |
465 | Arr_2_Glob [8][7] = 10;
466 |
467 | /* Was missing in published program. Without this statement, */
468 | /* Arr_2_Glob [8][7] would have an undefined value. */
469 | /* Warning: With 16-Bit processors and Number_Of_Runs > 32000, */
470 | /* overflow may occur for this array element. */
471 |
472 | printf ("\n");
473 | printf ("Dhrystone Benchmark, Version 2.1 (Language: D)\n");
474 | printf ("\n");
475 | printf ("Please give the number of runs through the benchmark: ");
476 | {
477 | int n;
478 |
479 | // scanf ("%d", &n);
480 | n = 10000000;
481 | Number_Of_Runs = n;
482 | }
483 | printf ("\n");
484 |
485 | printf ("Execution starts, %d runs through Dhrystone\n", Number_Of_Runs);
486 |
487 | /***************/
488 | /* Start timer */
489 | /***************/
490 |
491 | Begin_Time = dtime();
492 |
493 | for (Run_Index = 1; Run_Index <= Number_Of_Runs; ++Run_Index)
494 | {
495 | Proc_5();
496 | Proc_4();
497 |
498 | /* Ch_1_Glob == 'A', Ch_2_Glob == 'B', Bool_Glob == true */
499 | Int_1_Loc = 2;
500 | Int_2_Loc = 3;
501 |
502 | // strcpy (Str_2_Loc, "DHRYSTONE PROGRAM, 2'ND STRING");
503 | Str_2_Loc[] = "DHRYSTONE PROGRAM, 2'ND STRING";
504 | Enum_Loc = Ident_2;
505 | Bool_Glob = !Func_2 (Str_1_Loc, Str_2_Loc);
506 |
507 | /* Bool_Glob == 1 */
508 | while (Int_1_Loc < Int_2_Loc) /* loop body executed once */
509 | {
510 | Int_3_Loc = 5 * Int_1_Loc - Int_2_Loc;
511 |
512 | /* Int_3_Loc == 7 */
513 | Proc_7 (Int_1_Loc, Int_2_Loc, &Int_3_Loc);
514 |
515 | /* Int_3_Loc == 7 */
516 | Int_1_Loc += 1;
517 | } /* while */
518 |
519 | /* Int_1_Loc == 3, Int_2_Loc == 3, Int_3_Loc == 7 */
520 | Proc_8 (Arr_1_Glob, Arr_2_Glob, Int_1_Loc, Int_3_Loc);
521 |
522 | /* Int_Glob == 5 */
523 | Proc_1 (Ptr_Glob);
524 |
525 | for (Ch_Index = 'A'; Ch_Index <= Ch_2_Glob; ++Ch_Index)
526 | {
527 | /* loop body executed twice */
528 | if (Enum_Loc == Func_1 (Ch_Index, 'C'))
529 | {
530 | /* then, not executed */
531 | Proc_6 (Ident_1, &Enum_Loc);
532 |
533 | // strcpy (Str_2_Loc, "DHRYSTONE PROGRAM, 3'RD STRING");
534 | Str_2_Loc[] = "DHRYSTONE PROGRAM, 3'RD STRING";
535 | Int_2_Loc = Run_Index;
536 | Int_Glob = Run_Index;
537 | }
538 | }
539 |
540 | /* Int_1_Loc == 3, Int_2_Loc == 3, Int_3_Loc == 7 */
541 | Int_2_Loc = Int_2_Loc * Int_1_Loc;
542 | Int_1_Loc = Int_2_Loc / Int_3_Loc;
543 | Int_2_Loc = 7 * (Int_2_Loc - Int_3_Loc) - Int_1_Loc;
544 |
545 | /* Int_1_Loc == 1, Int_2_Loc == 13, Int_3_Loc == 7 */
546 | Proc_2 (&Int_1_Loc);
547 |
548 | /* Int_1_Loc == 5 */
549 | } /* loop "for Run_Index" */
550 |
551 | /**************/
552 | /* Stop timer */
553 | /**************/
554 |
555 | End_Time = dtime();
556 |
557 | printf ("Execution ends\n");
558 | printf ("\n");
559 | printf ("Final values of the variables used in the benchmark:\n");
560 | printf ("\n");
561 | printf ("Int_Glob: %d\n", Int_Glob);
562 | printf (" should be: %d\n", 5);
563 | printf ("Bool_Glob: %d\n", Bool_Glob);
564 | printf (" should be: %d\n", 1);
565 | printf ("Ch_1_Glob: %c\n", Ch_1_Glob);
566 | printf (" should be: %c\n", cast(int) 'A');
567 | printf ("Ch_2_Glob: %c\n", Ch_2_Glob);
568 | printf (" should be: %c\n", cast(int) 'B');
569 | printf ("Arr_1_Glob[8]: %d\n", Arr_1_Glob[8]);
570 | printf (" should be: %d\n", 7);
571 | printf ("Arr_2_Glob[8][7]: %d\n", Arr_2_Glob[8][7]);
572 | printf (" should be: Number_Of_Runs + 10\n");
573 | printf ("Ptr_Glob.\n");
574 | printf (" Ptr_Comp: %d\n", cast(int) Ptr_Glob.Ptr_Comp);
575 | printf (" should be: (implementation-dependent)\n");
576 | printf (" Discr: %d\n", Ptr_Glob.Discr);
577 | printf (" should be: %d\n", 0);
578 | printf (" Enum_Comp: %d\n", Ptr_Glob.variant.var_1.Enum_Comp);
579 | printf (" should be: %d\n", 2);
580 | printf (" Int_Comp: %d\n", Ptr_Glob.variant.var_1.Int_Comp);
581 | printf (" should be: %d\n", 17);
582 | printf (" Str_Comp: %.*s\n", cast(int) Ptr_Glob.variant.var_1.Str_Comp.length,
583 | Ptr_Glob.variant.var_1.Str_Comp.ptr);
584 | printf (" should be: DHRYSTONE PROGRAM, SOME STRING\n");
585 | printf ("Next_Ptr_Glob.\n");
586 | printf (" Ptr_Comp: %d\n", cast(int) Next_Ptr_Glob.Ptr_Comp);
587 | printf (" should be: (implementation-dependent), same as above\n");
588 | printf (" Discr: %d\n", Next_Ptr_Glob.Discr);
589 | printf (" should be: %d\n", 0);
590 | printf (" Enum_Comp: %d\n", Next_Ptr_Glob.variant.var_1.Enum_Comp);
591 | printf (" should be: %d\n", 1);
592 | printf (" Int_Comp: %d\n", Next_Ptr_Glob.variant.var_1.Int_Comp);
593 | printf (" should be: %d\n", 18);
594 | printf (" Str_Comp: %.*s\n", cast(int) Next_Ptr_Glob.variant.var_1.Str_Comp.length,
595 | Next_Ptr_Glob.variant.var_1.Str_Comp.ptr);
596 | printf (" should be: DHRYSTONE PROGRAM, SOME STRING\n");
597 | printf ("Int_1_Loc: %d\n", Int_1_Loc);
598 | printf (" should be: %d\n", 5);
599 | printf ("Int_2_Loc: %d\n", Int_2_Loc);
600 | printf (" should be: %d\n", 13);
601 | printf ("Int_3_Loc: %d\n", Int_3_Loc);
602 | printf (" should be: %d\n", 7);
603 | printf ("Enum_Loc: %d\n", Enum_Loc);
604 | printf (" should be: %d\n", 1);
605 | printf ("Str_1_Loc: %.*s\n", cast(int) Str_1_Loc.length, Str_1_Loc.ptr);
606 | printf (" should be: DHRYSTONE PROGRAM, 1'ST STRING\n");
607 | printf ("Str_2_Loc: %.*s\n", cast(int) Str_2_Loc.length, Str_2_Loc.ptr);
608 | printf (" should be: DHRYSTONE PROGRAM, 2'ND STRING\n");
609 | printf ("\n");
610 |
611 | User_Time = End_Time - Begin_Time;
612 |
613 | if (User_Time < Too_Small_Time)
614 | {
615 | printf ("Measured time too small to obtain meaningful results\n");
616 | printf ("Please increase number of runs\n");
617 | printf ("\n");
618 | }
619 | else
620 | {
621 | Microseconds = User_Time * Mic_secs_Per_Second
622 | / cast(double) Number_Of_Runs;
623 | Dhrystones_Per_Second = cast(double) Number_Of_Runs / User_Time;
624 | Vax_Mips = Dhrystones_Per_Second / 1757.0;
625 |
626 | printf ("Register option selected? NO\n");
627 | strcpy(Reg_Define.ptr, "Register option not selected.");
628 | printf ("Microseconds for one run through Dhrystone: ");
629 | printf ("%7.1lf \n", Microseconds);
630 | printf ("Dhrystones per Second: ");
631 | printf ("%10.1lf \n", Dhrystones_Per_Second);
632 | printf ("VAX MIPS rating = %10.3lf \n", Vax_Mips);
633 | printf ("\n");
634 |
635 | fprintf(Ap, "\n");
636 | fprintf(Ap, "Dhrystone Benchmark, Version 2.1 (Language: D)\n");
637 | fprintf(Ap, "%*s\n", Reg_Define.ptr);
638 | fprintf(Ap, "Microseconds for one loop: %7.1lf\n", Microseconds);
639 | fprintf(Ap, "Dhrystones per second: %10.1lf\n", Dhrystones_Per_Second);
640 | fprintf(Ap, "VAX MIPS rating: %10.3lf\n", Vax_Mips);
641 | fclose(Ap);
642 | }
643 | }
644 |
645 | void Proc_1(Rec_Pointer Ptr_Val_Par)
646 |
647 | /******************/
648 |
649 | /* executed once */
650 | {
651 | Rec_Pointer Next_Record = Ptr_Val_Par.Ptr_Comp;
652 |
653 | /* == Ptr_Glob_Next */
654 | /* Local variable, initialized with Ptr_Val_Par.Ptr_Comp, */
655 | /* corresponds to "rename" in Ada, "with" in Pascal */
656 |
657 | *Ptr_Val_Par.Ptr_Comp = *Ptr_Glob;
658 | Ptr_Val_Par.variant.var_1.Int_Comp = 5;
659 | Next_Record.variant.var_1.Int_Comp
660 | = Ptr_Val_Par.variant.var_1.Int_Comp;
661 | Next_Record.Ptr_Comp = Ptr_Val_Par.Ptr_Comp;
662 | Proc_3 (&Next_Record.Ptr_Comp);
663 |
664 | /* Ptr_Val_Par.Ptr_Comp.Ptr_Comp
665 | == Ptr_Glob.Ptr_Comp */
666 | if (Next_Record.Discr == Ident_1)
667 | {
668 | /* then, executed */
669 | Next_Record.variant.var_1.Int_Comp = 6;
670 | Proc_6 (Ptr_Val_Par.variant.var_1.Enum_Comp,
671 | &Next_Record.variant.var_1.Enum_Comp);
672 | Next_Record.Ptr_Comp = Ptr_Glob.Ptr_Comp;
673 | Proc_7 (Next_Record.variant.var_1.Int_Comp, 10,
674 | &Next_Record.variant.var_1.Int_Comp);
675 | }
676 | else /* not executed */
677 | *Ptr_Val_Par = *Ptr_Val_Par.Ptr_Comp;
678 | } /* Proc_1 */
679 | void Proc_2(One_Fifty *Int_Par_Ref)
680 |
681 | /******************/
682 | /* executed once */
683 | /* *Int_Par_Ref == 1, becomes 4 */
684 | {
685 | One_Fifty Int_Loc;
686 | Enumeration Enum_Loc;
687 |
688 | Int_Loc = *Int_Par_Ref + 10;
689 |
690 | do /* executed once */
691 | if (Ch_1_Glob == 'A')
692 | {
693 | /* then, executed */
694 | Int_Loc -= 1;
695 | *Int_Par_Ref = Int_Loc - Int_Glob;
696 | Enum_Loc = Ident_1;
697 | }
698 |
699 | /* if */
700 | while (Enum_Loc != Ident_1); /* true */
701 | } /* Proc_2 */
702 | void Proc_3(Rec_Pointer *Ptr_Ref_Par)
703 |
704 | /******************/
705 | /* executed once */
706 | /* Ptr_Ref_Par becomes Ptr_Glob */
707 | {
708 | if (Ptr_Glob != null)
709 | /* then, executed */
710 | *Ptr_Ref_Par = Ptr_Glob.Ptr_Comp;
711 |
712 | Proc_7 (10, Int_Glob, &Ptr_Glob.variant.var_1.Int_Comp);
713 | } /* Proc_3 */
714 | void Proc_4() /* without parameters */
715 | /*******/
716 | /* executed once */
717 | {
718 | Boolean Bool_Loc;
719 |
720 | Bool_Loc = Ch_1_Glob == 'A';
721 | Bool_Glob = Bool_Loc | Bool_Glob;
722 | Ch_2_Glob = 'B';
723 | } /* Proc_4 */
724 | void Proc_5() /* without parameters */
725 | /*******/
726 | /* executed once */
727 | {
728 | Ch_1_Glob = 'A';
729 | Bool_Glob = false;
730 | } /* Proc_5 */
731 | void Proc_6(Enumeration Enum_Val_Par, Enumeration *Enum_Ref_Par)
732 |
733 | /*********************************/
734 | /* executed once */
735 | /* Enum_Val_Par == Ident_3, Enum_Ref_Par becomes Ident_2 */
736 | {
737 | *Enum_Ref_Par = Enum_Val_Par;
738 |
739 | if (!Func_3 (Enum_Val_Par))
740 | /* then, not executed */
741 | *Enum_Ref_Par = Ident_4;
742 |
743 | switch (Enum_Val_Par)
744 | {
745 | case Ident_1:
746 | *Enum_Ref_Par = Ident_1;
747 | break;
748 |
749 | case Ident_2:
750 |
751 | if (Int_Glob > 100)
752 | /* then */
753 | *Enum_Ref_Par = Ident_1;
754 | else *Enum_Ref_Par = Ident_4;
755 |
756 | break;
757 |
758 | case Ident_3: /* executed */
759 | *Enum_Ref_Par = Ident_2;
760 | break;
761 |
762 | case Ident_4:
763 | break;
764 |
765 | case Ident_5:
766 | *Enum_Ref_Par = Ident_3;
767 | break;
768 |
769 | default:
770 | } /* switch */
771 |
772 | } /* Proc_6 */
773 | void Proc_7(One_Fifty Int_1_Par_Val, One_Fifty Int_2_Par_Val, One_Fifty *Int_Par_Ref)
774 |
775 | /**********************************************/
776 | /* executed three times */
777 | /* first call: Int_1_Par_Val == 2, Int_2_Par_Val == 3, */
778 | /* Int_Par_Ref becomes 7 */
779 | /* second call: Int_1_Par_Val == 10, Int_2_Par_Val == 5, */
780 | /* Int_Par_Ref becomes 17 */
781 | /* third call: Int_1_Par_Val == 6, Int_2_Par_Val == 10, */
782 | /* Int_Par_Ref becomes 18 */
783 | {
784 | One_Fifty Int_Loc;
785 |
786 | Int_Loc = Int_1_Par_Val + 2;
787 | *Int_Par_Ref = Int_2_Par_Val + Int_Loc;
788 | } /* Proc_7 */
789 | void Proc_8(ref Arr_1_Dim Arr_1_Par_Ref, ref Arr_2_Dim Arr_2_Par_Ref, int Int_1_Par_Val, int Int_2_Par_Val)
790 |
791 | /*********************************************************************/
792 | /* executed once */
793 | /* Int_Par_Val_1 == 3 */
794 | /* Int_Par_Val_2 == 7 */
795 | {
796 | One_Fifty Int_Index;
797 | One_Fifty Int_Loc;
798 |
799 | Int_Loc = Int_1_Par_Val + 5;
800 | Arr_1_Par_Ref [Int_Loc] = Int_2_Par_Val;
801 | Arr_1_Par_Ref [Int_Loc + 1] = Arr_1_Par_Ref [Int_Loc];
802 | Arr_1_Par_Ref [Int_Loc + 30] = Int_Loc;
803 |
804 | for (Int_Index = Int_Loc; Int_Index <= Int_Loc + 1; ++Int_Index)
805 | Arr_2_Par_Ref [Int_Loc] [Int_Index] = Int_Loc;
806 |
807 | Arr_2_Par_Ref [Int_Loc] [Int_Loc - 1] += 1;
808 | Arr_2_Par_Ref [Int_Loc + 20] [Int_Loc] = Arr_1_Par_Ref [Int_Loc];
809 | Int_Glob = 5;
810 | } /* Proc_8 */
811 | Enumeration Func_1(Capital_Letter Ch_1_Par_Val, Capital_Letter Ch_2_Par_Val)
812 |
813 | /*************************************************/
814 | /* executed three times */
815 | /* first call: Ch_1_Par_Val == 'H', Ch_2_Par_Val == 'R' */
816 | /* second call: Ch_1_Par_Val == 'A', Ch_2_Par_Val == 'C' */
817 | /* third call: Ch_1_Par_Val == 'B', Ch_2_Par_Val == 'C' */
818 | {
819 | Capital_Letter Ch_1_Loc;
820 | Capital_Letter Ch_2_Loc;
821 |
822 | Ch_1_Loc = Ch_1_Par_Val;
823 | Ch_2_Loc = Ch_1_Loc;
824 |
825 | if (Ch_2_Loc != Ch_2_Par_Val)
826 | /* then, executed */
827 | return (Ident_1);
828 | else /* not executed */
829 | {
830 | Ch_1_Glob = Ch_1_Loc;
831 | return (Ident_2);
832 | }
833 | } /* Func_1 */
834 | Boolean Func_2(Str_30 Str_1_Par_Ref, Str_30 Str_2_Par_Ref)
835 |
836 | /*************************************************/
837 | /* executed once */
838 | /* Str_1_Par_Ref == "DHRYSTONE PROGRAM, 1'ST STRING" */
839 | /* Str_2_Par_Ref == "DHRYSTONE PROGRAM, 2'ND STRING" */
840 | {
841 | One_Thirty Int_Loc;
842 | Capital_Letter Ch_Loc;
843 |
844 | Int_Loc = 2;
845 |
846 | while (Int_Loc <= 2) /* loop body executed once */
847 | if (Func_1 (Str_1_Par_Ref[Int_Loc],
848 | Str_2_Par_Ref[Int_Loc + 1]) == Ident_1)
849 | {
850 | /* then, executed */
851 | Ch_Loc = 'A';
852 | Int_Loc += 1;
853 | }
854 |
855 | /* if, while */
856 |
857 | if (Ch_Loc >= 'W' && Ch_Loc < 'Z')
858 | /* then, not executed */
859 | Int_Loc = 7;
860 |
861 | if (Ch_Loc == 'R')
862 | /* then, not executed */
863 | return (true);
864 | else /* executed */
865 | {
866 | // if (strcmp (Str_1_Par_Ref, Str_2_Par_Ref) > 0)
867 | // if (memcmp (Str_1_Par_Ref, Str_2_Par_Ref, 30) > 0)
868 | if (Str_1_Par_Ref > Str_2_Par_Ref)
869 | {
870 | /* then, not executed */
871 | Int_Loc += 7;
872 | Int_Glob = Int_Loc;
873 | return (true);
874 | }
875 | else /* executed */
876 | return (false);
877 | } /* if Ch_Loc */
878 |
879 | } /* Func_2 */
880 | Boolean Func_3(Enumeration Enum_Par_Val)
881 |
882 | /***************************/
883 | /* executed once */
884 | /* Enum_Par_Val == Ident_3 */
885 | {
886 | Enumeration Enum_Loc;
887 |
888 | Enum_Loc = Enum_Par_Val;
889 |
890 | if (Enum_Loc == Ident_3)
891 | /* then, executed */
892 | return (true);
893 | else /* not executed */
894 | return (false);
895 | } /* Func_3 */
896 |
897 | version (Windows)
898 | {
899 | import core.sys.windows.winbase;
900 |
901 | double dtime()
902 | {
903 | double q;
904 |
905 | q = cast(double) GetTickCount() * 1.0e-03;
906 |
907 | return q;
908 | }
909 | }
910 |
911 | version (linux)
912 | {
913 | import core.stdc.time;
914 |
915 | double dtime()
916 | {
917 | double q;
918 |
919 | q = cast(double) time(null);
920 |
921 | return q;
922 | }
923 | }
924 |
925 | version (OSX) // supplied by Anders F Bjorklund
926 | {
927 | import core.sys.posix.sys.time;
928 |
929 | double dtime()
930 | {
931 | double q;
932 | timeval tv;
933 |
934 | gettimeofday(&tv, null);
935 | q = cast(double) tv.tv_sec + cast(double) tv.tv_usec * 1.0e-6;
936 |
937 | return q;
938 | }
939 | }
940 |
--------------------------------------------------------------------------------