Diff
Not logged in

Differences From Artifact [d70e48b147acc242]:

To Artifact [c96de2738d81e418]:


4 * 4 * 5 * Common tricks and utilities for programming in D. 5 * Common tricks and utilities for programming in D. 6 */ 6 */ 7 module tricks.tricks; 7 module tricks.tricks; 8 import tricks.test; 8 import tricks.test; 9 import std.array : appender; 9 import std.array : appender; 10 import std.format : formattedWrite; 10 import std.format : formattedWrite; 11 import core.exception : AssertError; | 11 import core.exception; > 12 import std.traits; > 13 import std.typetuple; 12 14 13 /// Simple Wrapper for std.format.doFormat 15 /// Simple Wrapper for std.format.doFormat 14 16 15 string sprintf(string fmt, T...)(T params) 17 string sprintf(string fmt, T...)(T params) 16 { 18 { 17 auto writer = appender!string(); 19 auto writer = appender!string(); 18 formattedWrite(writer, fmt, params); 20 formattedWrite(writer, fmt, params); ................................................................................................................................................................................ 204 /*mixin*/ 206 /*mixin*/ 205 template SimpleClass() 207 template SimpleClass() 206 { 208 { 207 mixin SimpleConstructor; 209 mixin SimpleConstructor; 208 mixin SimpleCompare; 210 mixin SimpleCompare; 209 mixin SimpleToString; 211 mixin SimpleToString; 210 } 212 } > 213 > 214 /// Simple PatternMatcher > 215 > 216 /*mixin*/ > 217 template SimplePatternMatch() > 218 { > 219 SPM_Return!(PP) match(string fn=__FILE__, size_t ln=__LINE__, PP...)(PP > 220 { > 221 foreach(i,_; pts) > 222 { > 223 alias pts[i] pt; // bug? pts[i]-->pt do not work > 224 static if(__traits(compiles, SPM_isMatchTag(pt))) > 225 { > 226 if( auto v = cast(pt.dynamicType)this ) > 227 return pt(v.tupleof); > 228 } > 229 else > 230 static if(__traits(compiles, SPM_isMatchAny(pt))) > 231 { > 232 return pt(); > 233 } > 234 else > 235 { > 236 if( auto v = cast(SPM_PTT!(pt)[0])this ) > 237 return pt(v); > 238 } > 239 } > 240 SPM_throwAssertError(fn, ln, "pattern matching failure"); > 241 assert(false); > 242 } > 243 } > 244 > 245 /// Pattern case clause > 246 > 247 SPM_MatchTag!(T, fn) when(T, alias fn)() > 248 { > 249 SPM_MatchTag!(T, fn) m; > 250 return m; > 251 } > 252 > 253 /// Pattern case clause > 254 > 255 SPM_MatchAny!(fn) otherwise(alias fn)() > 256 { > 257 SPM_MatchAny!(fn) m; > 258 return m; > 259 } > 260 > 261 // implementation detail of SimplePatternMatch > 262 > 263 void SPM_throwAssertError(T...)(T t) { core.exception.onAssertErrorMsg(t); } > 264 > 265 struct SPM_MatchTag(T, alias fn) > 266 { > 267 alias T dynamicType; > 268 auto opCall(typeof(T.tupleof) s) { return fn(s); } > 269 } > 270 > 271 struct SPM_MatchAny(alias fn) > 272 { > 273 auto opCall() { return fn(); } > 274 } > 275 > 276 template SPM_PTT(alias p) > 277 { > 278 alias ParameterTypeTuple!(p) SPM_PTT; > 279 } > 280 > 281 template SPM_Each(P) > 282 { > 283 static if(__traits(compiles, SPM_isMatchTag(P.init))) > 284 alias typeof(P(P.dynamicType.tupleof)) SPM_Each; > 285 else > 286 static if(__traits(compiles, SPM_isMatchAny(P.init))) > 287 alias typeof(P()) SPM_Each; > 288 else > 289 alias ReturnType!(P) SPM_Each; > 290 } > 291 > 292 template SPM_aVoid(T:void, TS...) { alias SPM_aVoid!(TS) SPM_aVoid; } > 293 template SPM_aVoid(T, TS...) { alias TypeTuple!(T,SPM_aVoid!(TS)) SPM_aVoid; } > 294 template SPM_aVoid() { alias TypeTuple!() SPM_aVoid; } > 295 > 296 template SPM_Return(PP...) > 297 { > 298 alias CommonType!(SPM_aVoid!(staticMap!(SPM_Each, PP))) SPM_Return; > 299 } > 300 > 301 void SPM_isMatchTag(T,alias fn)(SPM_MatchTag!(T,fn)){} > 302 void SPM_isMatchAny(alias fn)(SPM_MatchAny!(fn)){} > 303 > 304 unittest > 305 { > 306 static abstract class Base { > 307 mixin SimplePatternMatch; > 308 } > 309 class D1 : Base { > 310 int x; > 311 real y; > 312 mixin SimpleConstructor; > 313 } > 314 class D2 : Base { > 315 string s; > 316 mixin SimpleConstructor; > 317 } > 318 class D3 : Base { > 319 int[int]m; > 320 mixin SimpleConstructor; > 321 } > 322 > 323 Base d1 = new D1(1, 2.3); > 324 Base d2 = new D2("foobar"); > 325 Base d3 = new D3(null); (cast(D3)d3).m[1]=10; > 326 > 327 // normal dispatch > 328 assert_eq( d1.match( > 329 (D1 x){return 1;}, > 330 (D2 x){return 2;}, > 331 ), 1); > 332 assert_eq( d2.match( > 333 (D1 x){return 1;}, > 334 (D2 x){return 2;}, > 335 ), 2); > 336 assert_throw!AssertError( d3.match( > 337 (D1 x){return 1;}, > 338 (D2 x){return 2;}, > 339 )); > 340 assert_eq( d3.match( > 341 (D1 x){return 1;}, > 342 (D2 x){return 2;}, > 343 (Base x){return 3;}, > 344 ), 3); > 345 assert_eq( d2.match( > 346 (D1 x){return 1;}, > 347 (D2 x){return 2;}, > 348 (Base x){return 3;}, > 349 ), 2); > 350 assert_eq( d2.match( > 351 (D1 x){return 1;}, > 352 (Base x){return 3;}, > 353 (D2 x){return 2;}, > 354 ), 3); > 355 > 356 // member decomposing match > 357 assert_eq( d1.match( > 358 when!(D1, (x, y){return x + cast(int)y;}), > 359 when!(D2, (x){return x.length;}), > 360 when!(D3, (x){return x[1];}), > 361 ), 3); > 362 assert_eq( d2.match( > 363 when!(D1, (x, y){return x + cast(int)y;}), > 364 when!(D2, (x){return x.length;}), > 365 when!(D3, (x){return x[1];}), > 366 ), 6); > 367 assert_eq( d3.match( > 368 when!(D1, (x, y){return x + cast(int)y;}), > 369 when!(D2, (x){return x.length;}), > 370 when!(D3, (x){return x[1];}), > 371 ), 10); > 372 assert_throw!AssertError( d3.match( > 373 when!(D1, (x, y){return x + cast(int)y;}), > 374 when!(D2, (x){return x.length;}), > 375 )); > 376 assert_eq( d2.match( > 377 when!(D1, (x, y){return x + cast(int)y;}), > 378 when!(D2, (x){return x.length;}), > 379 otherwise!({return 999;}), > 380 ), 6); > 381 assert_eq( d2.match( > 382 when!(D1, (x, y){return x + cast(int)y;}), > 383 otherwise!({return 999;}), > 384 when!(D2, (x){return x.length;}), > 385 ), 999); > 386 }