@@ -99,8 +99,21 @@ class Tamp : Tomp { mixin SimpleConstructor; } }) ); } +/// Mixing-in the MOST-DERIVED-member-wise comparator for a class + +template SimpleToHash() +{ + override hash_t toHash() const /// member-by-member hash + { + hash_t h = 0; + foreach(mem; this.tupleof) + h += typeid(mem).getHash(&mem); + return h; + } +} + /// Mixing-in the MOST-DERIVED-member-wise comparator for a class /*mixin*/ template SimpleCompare() @@ -115,16 +128,10 @@ return true; } assert(false, sprintf!"Cannot compare %s with %s"(typeid(this), typeid(rhs_))); } - - override hash_t toHash() const /// member-by-member hash - { - hash_t h = 0; - foreach(mem; this.tupleof) - h += typeid(mem).getHash(&mem); - return h; - } + + mixin SimpleToHash; override int opCmp(Object rhs_) const /// member-by-member compare { if( auto rhs = cast(typeof(this))rhs_ ) @@ -218,184 +225,10 @@ mixin SimpleCompare; mixin SimpleToString; } -/// Simple PatternMatcher - -/*mixin*/ -template SimplePatternMatch() -{ - SPM_Return!(PP) match(string fn=__FILE__, size_t ln=__LINE__, PP...)(PP pts) - { - foreach(i,_; pts) - { - alias pts[i] pt; // bug? pts[i]-->pt do not work - static if(__traits(compiles, SPM_isMatchTag(pt))) - { - if( auto v = cast(pt.dynamicType)this ) - return pt(v.tupleof); - } - else - static if(__traits(compiles, SPM_isMatchAny(pt))) - { - return pt(); - } - else - { - if( auto v = cast(SPM_PTT!(pt)[0])this ) - return pt(v); - } - } - SPM_throwAssertError(fn, ln, "pattern matching failure"); - assert(false); - } -} - -/// Pattern case clause - -SPM_MatchTag!(T, fn) when(T, alias fn)() -{ - SPM_MatchTag!(T, fn) m; - return m; -} - -/// Pattern case clause - -SPM_MatchAny!(fn) otherwise(alias fn)() -{ - SPM_MatchAny!(fn) m; - return m; -} - -// implementation detail of SimplePatternMatch - -void SPM_throwAssertError(T...)(T t) { core.exception.onAssertErrorMsg(t); } - -struct SPM_MatchTag(T, alias fn) -{ - alias T dynamicType; - auto opCall(typeof(T.tupleof) s) { return fn(s); } -} - -struct SPM_MatchAny(alias fn) -{ - auto opCall() { return fn(); } -} - -template SPM_PTT(alias p) -{ - alias ParameterTypeTuple!(p) SPM_PTT; -} - -template SPM_Each(P) -{ - static if(__traits(compiles, SPM_isMatchTag(P.init))) - alias typeof(P(P.dynamicType.tupleof)) SPM_Each; - else - static if(__traits(compiles, SPM_isMatchAny(P.init))) - alias typeof(P()) SPM_Each; - else - alias ReturnType!(P) SPM_Each; -} - -template SPM_aVoid(T:void, TS...) { alias SPM_aVoid!(TS) SPM_aVoid; } -template SPM_aVoid(T, TS...) { alias TypeTuple!(T,SPM_aVoid!(TS)) SPM_aVoid; } -template SPM_aVoid() { alias TypeTuple!() SPM_aVoid; } - -template SPM_Return(PP...) -{ - alias CommonType!(SPM_aVoid!(staticMap!(SPM_Each, PP))) SPM_Return; -} - -void SPM_isMatchTag(T,alias fn)(SPM_MatchTag!(T,fn)){} -void SPM_isMatchAny(alias fn)(SPM_MatchAny!(fn)){} - -unittest -{ - static abstract class Base { - mixin SimplePatternMatch; - } - class D1 : Base { - int x; - real y; - mixin SimpleConstructor; - } - class D2 : Base { - string s; - mixin SimpleConstructor; - } - class D3 : Base { - int[int] m; - mixin SimpleConstructor; - } - - Base d1 = new D1(1, 2.3); - Base d2 = new D2("foobar"); - Base d3 = new D3(null); (cast(D3)d3).m[1]=10; - - // normal dispatch - assert_eq( d1.match( - (D1 x){return 1;}, - (D2 x){return 2;} - ), 1); - assert_eq( d2.match( - (D1 x){return 1;}, - (D2 x){return 2;} - ), 2); - assert_throw!AssertError( d3.match( - (D1 x){return 1;}, - (D2 x){return 2;} - )); - assert_eq( d3.match( - (D1 x){return 1;}, - (D2 x){return 2;}, - (Base x){return 3;} - ), 3); - assert_eq( d2.match( - (D1 x){return 1;}, - (D2 x){return 2;}, - (Base x){return 3;} - ), 2); - assert_eq( d2.match( - (D1 x){return 1;}, - (Base x){return 3;}, - (D2 x){return 2;} - ), 3); - - // member decomposing match - assert_eq( d1.match( - when!(D1, (x, y){return x + cast(int)y;}), - when!(D2, (x){return x.length;}), - when!(D3, (x){return x[1];}) - ), 3); - assert_eq( d2.match( - when!(D1, (x, y){return x + cast(int)y;}), - when!(D2, (x){return x.length;}), - when!(D3, (x){return x[1];}) - ), 6); - assert_eq( d3.match( - when!(D1, (x, y){return x + cast(int)y;}), - when!(D2, (x){return x.length;}), - when!(D3, (x){return x[1];}) - ), 10); - assert_throw!AssertError( d3.match( - when!(D1, (x, y){return x + cast(int)y;}), - when!(D2, (x){return x.length;}) - )); - assert_eq( d2.match( - when!(D1, (x, y){return x + cast(int)y;}), - when!(D2, (x){return x.length;}), - otherwise!({return 999;}) - ), 6); - assert_eq( d2.match( - when!(D1, (x, y){return x + cast(int)y;}), - otherwise!({return 999;}), - when!(D2, (x){return x.length;}) - ), 999); -} - /// Will be used for dynamic overload resolution pattern template firstParam(T) { alias ParameterTypeTuple!(T)[0] firstParam; }