Mercurial > projects > mde
comparison mde/lookup/Options.d @ 98:49e7cfed4b34
All types of Option have been converted to use ValueContent classes, and their values can be displayed.
author | Diggory Hardy <diggory.hardy@gmail.com> |
---|---|
date | Wed, 12 Nov 2008 13:18:51 +0000 |
parents | 2a364c7d82c9 |
children | 71f0f1f83620 |
comparison
equal
deleted
inserted
replaced
97:30470bc19ca4 | 98:49e7cfed4b34 |
---|---|
79 protected this() {} /// Do not instantiate directly. | 79 protected this() {} /// Do not instantiate directly. |
80 | 80 |
81 // All supported types, for generic handling via templates. It should be possible to change | 81 // All supported types, for generic handling via templates. It should be possible to change |
82 // the supported types simply by changing this list now (untested). | 82 // the supported types simply by changing this list now (untested). |
83 template store(A...) { alias A store; } | 83 template store(A...) { alias A store; } |
84 alias store!(bool, int, double, char[]) TYPES; | 84 // NOTE: currently all types have transitioned to the new method, but the old method remains |
85 alias store!(int, double, char[]) TYPES2; | 85 alias store!(bool, int, double, char[]) TYPES; // all types |
86 alias store!(bool, int, double, char[]) CTYPES; // types stored with a content | |
86 //BEGIN Templates: internal | 87 //BEGIN Templates: internal |
87 private { | 88 private { |
88 // Get name of a type. Basically just stringof, but special handling for arrays. | 89 // Get name of a type. Basically just stringof, but special handling for arrays. |
89 // Use TName!(T) for a valid symbol name, and T.stringof for a type. | 90 // Use TName!(T) for a valid symbol name, and T.stringof for a type. |
90 template TName(T : T[]) { | 91 template TName(T : T[]) { |
95 } | 96 } |
96 | 97 |
97 // Pointer lists | 98 // Pointer lists |
98 template PLists(A...) { | 99 template PLists(A...) { |
99 static if (A.length) { | 100 static if (A.length) { |
100 static if (is (T == bool)) { | 101 static if (TIsIn!(A[0], CTYPES)) { |
101 const char[] PLists = PLists!(A[1..$]); | 102 const char[] PLists = PLists!(A[1..$]); |
102 } else | 103 } else |
103 const char[] PLists = A[0].stringof~"*[ID] opts"~TName!(A[0])~";\n" ~ PLists!(A[1..$]); | 104 const char[] PLists = A[0].stringof~"*[ID] opts"~TName!(A[0])~";\n" ~ PLists!(A[1..$]); |
104 } else | 105 } else |
105 const char[] PLists = ""; | 106 const char[] PLists = ""; |
116 const bool TIsIn = false; // no more possibilities | 117 const bool TIsIn = false; // no more possibilities |
117 } | 118 } |
118 | 119 |
119 // For addTag | 120 // For addTag |
120 template addTagMixin(T, A...) { | 121 template addTagMixin(T, A...) { |
121 static if (is(T == bool)) { | 122 static if (TIsIn!(T, CTYPES)) { |
122 const char[] ifBlock = `if (tp == "`~T.stringof~`") { | 123 const char[] ifBlock = `if (tp == "`~T.stringof~`") { |
123 auto p = id in opts; | 124 auto p = id in opts; |
124 if (p) { | 125 if (p) { |
125 auto q = cast(BoolContent) (*p); | 126 auto q = cast(`~VContentN!(T)~`) (*p); |
126 if (q) q.v = parseTo!(`~T.stringof~`) (dt); | 127 if (q) q.v = parseTo!(`~T.stringof~`) (dt); |
127 } | 128 } |
128 }`; | 129 }`; |
129 } else | 130 } else |
130 const char[] ifBlock = `if (tp == "`~T.stringof~`") { | 131 const char[] ifBlock = `if (tp == "`~T.stringof~`") { |
138 } | 139 } |
139 | 140 |
140 // For list | 141 // For list |
141 template listMixin(A...) { | 142 template listMixin(A...) { |
142 static if (A.length) { | 143 static if (A.length) { |
143 const char[] listMixin = `ret ~= opts`~TName!(A[0])~`.keys;` ~ listMixin!(A[1..$]); | 144 static if (TIsIn!(A, CTYPES)) |
145 const char[] listMixin = listMixin!(A[1..$]); | |
146 else | |
147 const char[] listMixin = `ret ~= opts`~TName!(A[0])~`.keys;` ~ listMixin!(A[1..$]); | |
144 } else | 148 } else |
145 const char[] listMixin = ``; | 149 const char[] listMixin = ``; |
146 } | 150 } |
147 } | 151 } |
148 //END Templates: internal | 152 //END Templates: internal |
246 * | 250 * |
247 * Due to the way options are handled generically, string IDs must be used to access the options | 251 * Due to the way options are handled generically, string IDs must be used to access the options |
248 * via hash-maps, which is a little slower than direct access but necessary since the option | 252 * via hash-maps, which is a little slower than direct access but necessary since the option |
249 * must be changed in two separate places. */ | 253 * must be changed in two separate places. */ |
250 void set(T) (char[] symbol, T val) { | 254 void set(T) (char[] symbol, T val) { |
251 static assert (TIsIn!(T,TYPES) && !is(T == bool), "Options does not support type "~T.stringof); | 255 static assert (TIsIn!(T,TYPES) && !TIsIn!(T, CTYPES), "Options.set does not support type "~T.stringof); |
252 | 256 |
253 changed = true; // something got set (don't bother checking this isn't what it already was) | 257 changed = true; // something got set (don't bother checking this isn't what it already was) |
254 | 258 |
255 try { | 259 try { |
256 mixin (`*(opts`~TName!(T)~`[cast(ID) symbol]) = val;`); | 260 mixin (`*(opts`~TName!(T)~`[cast(ID) symbol]) = val;`); |
278 }+/ | 282 }+/ |
279 | 283 |
280 /** List the names of all options of a specific type. */ | 284 /** List the names of all options of a specific type. */ |
281 char[][] list () { | 285 char[][] list () { |
282 char[][] ret; | 286 char[][] ret; |
283 mixin (listMixin!(TYPES2)); | 287 mixin (listMixin!(TYPES)); |
284 return ret; | 288 return ret; |
285 } | 289 } |
286 | 290 |
287 /// Get all Options stored with a ValueContent. | 291 /// Get all Options stored with a ValueContent. |
288 ValueContent[char[]] content() { | 292 ValueContent[char[]] content() { |
295 protected { | 299 protected { |
296 char[] secName; // name of this option setting; set null after translation is loaded | 300 char[] secName; // name of this option setting; set null after translation is loaded |
297 OptionChanges optionChanges; // all changes to options (for saving) | 301 OptionChanges optionChanges; // all changes to options (for saving) |
298 | 302 |
299 // The "pointer lists", e.g. char[]*[ID] optscharA; | 303 // The "pointer lists", e.g. char[]*[ID] optscharA; |
300 mixin (PLists!(TYPES2)); //FIXME | 304 mixin (PLists!(TYPES)); |
301 ValueContent[char[]] opts; // generic list of option values | 305 ValueContent[char[]] opts; // generic list of option values |
302 } | 306 } |
303 | 307 |
304 //BEGIN Mergetag loading/saving code | 308 //BEGIN Mergetag loading/saving code |
305 void addTag (char[] tp, ID id, char[] dt) { | 309 void addTag (char[] tp, ID id, char[] dt) { |
313 | 317 |
314 //BEGIN Templates: impl & optionsThis | 318 //BEGIN Templates: impl & optionsThis |
315 private { | 319 private { |
316 // Replace, e.g., bool, with BoolContent | 320 // Replace, e.g., bool, with BoolContent |
317 template contentName(A) { | 321 template contentName(A) { |
318 static if (is(A == bool)) { | 322 static if (TIsIn!(A, CTYPES)) { |
319 const char[] contentName = "BoolContent"; | 323 const char[] contentName = VContentN!(A); |
320 } else static if (is(A == int)) { | 324 } else |
321 const char[] contentName = "int";// no IntContent yet | 325 const char[] contentName = A.stringof; |
322 } else static if (is(A == double)) { | |
323 const char[] contentName = "double"; | |
324 } else static if (is(A == char[])) { | |
325 const char[] contentName = "char[]"; | |
326 } else | |
327 static assert (false, "unsuppurted type: "~ A); | |
328 } | 326 } |
329 // Return index of first comma, or halts if not found. | 327 // Return index of first comma, or halts if not found. |
330 template cIndex(char[] A) { | 328 template cIndex(char[] A) { |
331 static if (A.length == 0) | 329 static if (A.length == 0) |
332 static assert (false, "Error in implementation"); | 330 static assert (false, "Error in implementation"); |
368 else | 366 else |
369 const char[] aaVars = "\""~A[0..cIndex!(A)]~"\"[]:&"~A[0..cIndex!(A)] ~ "," ~ | 367 const char[] aaVars = "\""~A[0..cIndex!(A)]~"\"[]:&"~A[0..cIndex!(A)] ~ "," ~ |
370 aaVars!(A[cIndex!(A)+1..$]); | 368 aaVars!(A[cIndex!(A)+1..$]); |
371 } | 369 } |
372 // May have a trailing comma. Assumes cIndex always returns less than A.$ . | 370 // May have a trailing comma. Assumes cIndex always returns less than A.$ . |
373 template aaVarsBool(char[] A) {//FIXME | 371 template aaVarsContent(char[] A) {//FIXME |
374 static if (A.length == 0) | 372 static if (A.length == 0) |
375 const char[] aaVarsBool = ""; | 373 const char[] aaVarsContent = ""; |
376 else static if (A[0] == ' ') | 374 else static if (A[0] == ' ') |
377 const char[] aaVarsBool = aaVarsBool!(A[1..$]); | 375 const char[] aaVarsContent = aaVarsContent!(A[1..$]); |
378 else | 376 else |
379 const char[] aaVarsBool = "\""~A[0..cIndex!(A)]~"\"[]:"~A[0..cIndex!(A)] ~ "," ~ | 377 const char[] aaVarsContent = "\""~A[0..cIndex!(A)]~"\"[]:cast(ValueContent)"~A[0..cIndex!(A)] ~ "," ~ |
380 aaVarsBool!(A[cIndex!(A)+1..$]); | 378 aaVarsContent!(A[cIndex!(A)+1..$]); |
381 } | 379 } |
382 // strip Trailing Comma | 380 // strip Trailing Comma |
383 template sTC(char[] A) { | 381 template sTC(char[] A) { |
384 static if (A.length && A[$-1] == ',') | 382 static if (A.length && A[$-1] == ',') |
385 const char[] sTC = A[0..$-1]; | 383 const char[] sTC = A[0..$-1]; |
401 const char[] catOrNothing = A~` `~sTC!(B)~";\n"; | 399 const char[] catOrNothing = A~` `~sTC!(B)~";\n"; |
402 else | 400 else |
403 const char[] catOrNothing = ``; | 401 const char[] catOrNothing = ``; |
404 } | 402 } |
405 // foreach decl... | 403 // foreach decl... |
406 template createBCs(char[] A) { | 404 template createContents(T, char[] A) { |
407 static if (A.length == 0) | 405 static if (A.length == 0) |
408 const char[] createBCs = ""; | 406 const char[] createContents = ""; |
409 else static if (A[0] == ' ') | 407 else static if (A[0] == ' ') |
410 const char[] createBCs = createBCs!(A[1..$]); | 408 const char[] createContents = createContents!(T,A[1..$]); |
411 else | 409 else |
412 const char[] createBCs = A[0..cIndex!(A)]~ ` = (new BoolContent ("`~A[0..cIndex!(A)]~"\")).addChangeCb (&optionChanges.set);\n"~ | 410 const char[] createContents = "opts[\""~A[0..cIndex!(A)]~"\"] = " ~ A[0..cIndex!(A)]~ " = (new "~VContentN!(T)~" (\""~A[0..cIndex!(A)]~"\")).addChangeCb (&optionChanges.set);\n"~ |
413 createBCs!(A[cIndex!(A)+1..$]); | 411 createContents!(T,A[cIndex!(A)+1..$]); |
414 } | 412 } |
415 // for recursing on TYPES | 413 // for recursing on TYPES |
416 template optionsThisInternal(char[] A, B...) { | 414 template optionsThisInternal(char[] A, B...) { |
417 static if (B.length) { | 415 static if (B.length) { |
418 static if (is(B[0] == bool)) {//FIXME | 416 static if (TIsIn!(B[0], CTYPES)) { |
419 const char[] optionsThisInternal = createBCs!(parseT!(B[0].stringof,A))~ | 417 const char[] optionsThisInternal = createContents!(B[0],parseT!(B[0].stringof,A))~ |
420 `opts = `~listOrNull!(sTC!(aaVarsBool!(parseT!(B[0].stringof,A))))~";\n" ~ | |
421 optionsThisInternal!(A,B[1..$]); | 418 optionsThisInternal!(A,B[1..$]); |
422 } else | 419 } else |
423 const char[] optionsThisInternal = `opts`~TName!(B[0])~` = `~listOrNull!(sTC!(aaVars!(parseT!(B[0].stringof,A))))~";\n" ~ optionsThisInternal!(A,B[1..$]); | 420 const char[] optionsThisInternal = `opts`~TName!(B[0])~` = `~listOrNull!(sTC!(aaVars!(parseT!(B[0].stringof,A))))~";\n" ~ optionsThisInternal!(A,B[1..$]); |
424 } else | 421 } else |
425 const char[] optionsThisInternal = ``; | 422 const char[] optionsThisInternal = ``; |
555 */ | 552 */ |
556 | 553 |
557 /** A home for all miscellaneous options, at least for now. */ | 554 /** A home for all miscellaneous options, at least for now. */ |
558 MiscOptions miscOpts; | 555 MiscOptions miscOpts; |
559 class MiscOptions : Options { | 556 class MiscOptions : Options { |
560 const A = "bool exitImmediately; int maxThreads, logOptions; double pollInterval; char[] L10n;"; | 557 const A = "bool exitImmediately; int maxThreads, logLevel, logOutput; double pollInterval; char[] L10n;"; |
561 //pragma (msg, impl!(A)); | 558 //pragma (msg, impl!(A)); |
562 mixin (impl!(A)); | 559 mixin (impl!(A)); |
563 | 560 |
564 void validate() { | 561 void validate() { |
565 // Try to enforce sensible values, whilst being reasonably flexible: | 562 // Try to enforce sensible values, whilst being reasonably flexible: |
566 if (miscOpts.maxThreads < 1 || miscOpts.maxThreads > 64) { | 563 if (maxThreads() < 1 || maxThreads() > 64) { |
567 logger.warn ("maxThreads must be in the range 1-64. Defaulting to 4."); | 564 logger.warn ("maxThreads must be in the range 1-64. Defaulting to 4."); |
568 miscOpts.set!(int)("maxThreads", 4); | 565 maxThreads = 4; |
569 } | 566 } |
570 if (pollInterval !<= 1.0 || pollInterval !>= 0.0) | 567 if (pollInterval() !<= 1.0 || pollInterval() !>= 0.0) |
571 set!(double) ("pollInterval", 0.01); | 568 pollInterval = 0.01; |
572 } | 569 } |
573 | 570 |
574 static this() { | 571 static this() { |
575 miscOpts = new MiscOptions; | 572 miscOpts = new MiscOptions; |
576 Options.addOptionsClass (miscOpts, "MiscOptions"); | 573 Options.addOptionsClass (miscOpts, "MiscOptions"); |