Differences From Artifact [d70e48b147acc242]:
- File
tricks/tricks.d
- 2010-11-10 12:38:54 - part of checkin [38fcc662be] on branch trunk - cleaned up documentation comments (user: kinaba) [annotate]
To Artifact [c96de2738d81e418]:
- File
tricks/tricks.d
- 2010-11-13 02:48:58 - part of checkin [1c01f44f52] on branch trunk - simplepatternmatch (user: kinaba) [annotate]
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 }