8de5b49cdf 2010-11-09 kinaba: /** 8de5b49cdf 2010-11-09 kinaba: * Authors: k.inaba 8de5b49cdf 2010-11-09 kinaba: * License: NYSL 0.9982 http://www.kmonos.net/nysl/ 8de5b49cdf 2010-11-09 kinaba: * 8de5b49cdf 2010-11-09 kinaba: * Common tricks and utilities for programming in D. 8de5b49cdf 2010-11-09 kinaba: */ 8de5b49cdf 2010-11-09 kinaba: module tricks.tricks; 8de5b49cdf 2010-11-09 kinaba: import tricks.test; 1c01f44f52 2010-11-13 kinaba: import core.exception; 515502e8d1 2010-11-20 kinaba: import std.array : appender; 515502e8d1 2010-11-20 kinaba: import std.format : formattedWrite; 1c01f44f52 2010-11-13 kinaba: import std.traits; 1c01f44f52 2010-11-13 kinaba: import std.typetuple; 8de5b49cdf 2010-11-09 kinaba: 8de5b49cdf 2010-11-09 kinaba: /// Simple Wrapper for std.format.doFormat 8de5b49cdf 2010-11-09 kinaba: 8de5b49cdf 2010-11-09 kinaba: string sprintf(string fmt, T...)(T params) 8de5b49cdf 2010-11-09 kinaba: { 8de5b49cdf 2010-11-09 kinaba: auto writer = appender!string(); 8de5b49cdf 2010-11-09 kinaba: formattedWrite(writer, fmt, params); 8de5b49cdf 2010-11-09 kinaba: return writer.data; 8de5b49cdf 2010-11-09 kinaba: } 8de5b49cdf 2010-11-09 kinaba: 8de5b49cdf 2010-11-09 kinaba: unittest 8de5b49cdf 2010-11-09 kinaba: { 7de80acfb8 2010-11-09 kinaba: assert_eq( sprintf!"%s == %04d"("1+2", 3), "1+2 == 0003" ); 7de80acfb8 2010-11-09 kinaba: assert_eq( sprintf!"%2$s == %1$s"("1+2", 5, 8), "5 == 1+2" ); 7de80acfb8 2010-11-09 kinaba: assert_throw!Error( sprintf!"%s%s"(1) ); 8de5b49cdf 2010-11-09 kinaba: } 8de5b49cdf 2010-11-09 kinaba: 8de5b49cdf 2010-11-09 kinaba: /// Create an exception with automatically completed filename and lineno information 8de5b49cdf 2010-11-09 kinaba: 38fcc662be 2010-11-10 kinaba: ExceptionType genex(ExceptionType, string fn=__FILE__, int ln=__LINE__, T...)(T params) 8de5b49cdf 2010-11-09 kinaba: { 8de5b49cdf 2010-11-09 kinaba: static if( T.length > 0 && is(T[$-1] : Throwable) ) 8de5b49cdf 2010-11-09 kinaba: return new ExceptionType(params[0..$-1], fn, ln, params[$-1]); 8de5b49cdf 2010-11-09 kinaba: else 8de5b49cdf 2010-11-09 kinaba: return new ExceptionType(params, fn, ln); 8de5b49cdf 2010-11-09 kinaba: } 8de5b49cdf 2010-11-09 kinaba: 8de5b49cdf 2010-11-09 kinaba: unittest 8de5b49cdf 2010-11-09 kinaba: { 8de5b49cdf 2010-11-09 kinaba: assert_ne( genex!Exception("msg").file, "" ); 8de5b49cdf 2010-11-09 kinaba: assert_ne( genex!Exception("msg").line, 0 ); 8de5b49cdf 2010-11-09 kinaba: assert_ne( genex!Exception("msg",new Exception("bar")).next, Exception.init ); 8de5b49cdf 2010-11-09 kinaba: } 8de5b49cdf 2010-11-09 kinaba: 8de5b49cdf 2010-11-09 kinaba: /// Mixing-in the bean constructor for a class 8de5b49cdf 2010-11-09 kinaba: 8de5b49cdf 2010-11-09 kinaba: /*mixin*/ 8de5b49cdf 2010-11-09 kinaba: template SimpleConstructor() 8de5b49cdf 2010-11-09 kinaba: { 38fcc662be 2010-11-10 kinaba: /// member-by-member constructor 8de5b49cdf 2010-11-09 kinaba: static if( is(typeof(super) == Object) || super.tupleof.length==0 ) 8de5b49cdf 2010-11-09 kinaba: this( typeof(this.tupleof) params ) 8de5b49cdf 2010-11-09 kinaba: { 8de5b49cdf 2010-11-09 kinaba: static if(this.tupleof.length>0) 8de5b49cdf 2010-11-09 kinaba: this.tupleof = params; 8de5b49cdf 2010-11-09 kinaba: } 8de5b49cdf 2010-11-09 kinaba: else 8de5b49cdf 2010-11-09 kinaba: this( typeof(super.tupleof) ps, typeof(this.tupleof) params ) 8de5b49cdf 2010-11-09 kinaba: { 8de5b49cdf 2010-11-09 kinaba: // including (only) the direct super class members 8de5b49cdf 2010-11-09 kinaba: // may not always be a desirable choice, but should work for many cases 8de5b49cdf 2010-11-09 kinaba: super(ps); 8de5b49cdf 2010-11-09 kinaba: static if(this.tupleof.length>0) 8de5b49cdf 2010-11-09 kinaba: this.tupleof = params; 8de5b49cdf 2010-11-09 kinaba: } 8de5b49cdf 2010-11-09 kinaba: } 8de5b49cdf 2010-11-09 kinaba: 8de5b49cdf 2010-11-09 kinaba: unittest 8de5b49cdf 2010-11-09 kinaba: { 8de5b49cdf 2010-11-09 kinaba: class Temp 8de5b49cdf 2010-11-09 kinaba: { 8de5b49cdf 2010-11-09 kinaba: int x; 8de5b49cdf 2010-11-09 kinaba: string y; 8de5b49cdf 2010-11-09 kinaba: mixin SimpleConstructor; 8de5b49cdf 2010-11-09 kinaba: } 8de5b49cdf 2010-11-09 kinaba: assert_eq( (new Temp(1,"foo")).x, 1 ); 8de5b49cdf 2010-11-09 kinaba: assert_eq( (new Temp(1,"foo")).y, "foo" ); 8de5b49cdf 2010-11-09 kinaba: assert( !__traits(compiles, new Temp) ); 8de5b49cdf 2010-11-09 kinaba: assert( !__traits(compiles, new Temp(1)) ); 8de5b49cdf 2010-11-09 kinaba: assert( !__traits(compiles, new Temp("foo",1)) ); 8de5b49cdf 2010-11-09 kinaba: 8de5b49cdf 2010-11-09 kinaba: class Tomp : Temp 8de5b49cdf 2010-11-09 kinaba: { 8de5b49cdf 2010-11-09 kinaba: real z; 8de5b49cdf 2010-11-09 kinaba: mixin SimpleConstructor; 8de5b49cdf 2010-11-09 kinaba: } 8de5b49cdf 2010-11-09 kinaba: assert_eq( (new Tomp(1,"foo",2.5)).x, 1 ); 8de5b49cdf 2010-11-09 kinaba: assert_eq( (new Tomp(1,"foo",2.5)).y, "foo" ); 8de5b49cdf 2010-11-09 kinaba: assert_eq( (new Tomp(1,"foo",2.5)).z, 2.5 ); 8de5b49cdf 2010-11-09 kinaba: assert( !__traits(compiles, new Tomp(3.14)) ); 8de5b49cdf 2010-11-09 kinaba: 8de5b49cdf 2010-11-09 kinaba: // shiyo- desu. Don't use in this way. 8de5b49cdf 2010-11-09 kinaba: // Tamp tries to call new Tomp(real) (because it only sees Tomp's members), 8de5b49cdf 2010-11-09 kinaba: // but it fails because Tomp takes (int,string,real). 8de5b49cdf 2010-11-09 kinaba: assert( !__traits(compiles, { 38fcc662be 2010-11-10 kinaba: class Tamp : Tomp { mixin SimpleConstructor; } 8de5b49cdf 2010-11-09 kinaba: }) ); 38fcc662be 2010-11-10 kinaba: } 38fcc662be 2010-11-10 kinaba: 38fcc662be 2010-11-10 kinaba: /// Mixing-in the MOST-DERIVED-member-wise comparator for a class 38fcc662be 2010-11-10 kinaba: b97bd4f713 2010-11-23 kinaba: template SimpleToHash() b97bd4f713 2010-11-23 kinaba: { b97bd4f713 2010-11-23 kinaba: override hash_t toHash() const /// member-by-member hash b97bd4f713 2010-11-23 kinaba: { b97bd4f713 2010-11-23 kinaba: hash_t h = 0; b97bd4f713 2010-11-23 kinaba: foreach(mem; this.tupleof) b97bd4f713 2010-11-23 kinaba: h += typeid(mem).getHash(&mem); b97bd4f713 2010-11-23 kinaba: return h; b97bd4f713 2010-11-23 kinaba: } b97bd4f713 2010-11-23 kinaba: } b97bd4f713 2010-11-23 kinaba: b97bd4f713 2010-11-23 kinaba: /// Mixing-in the MOST-DERIVED-member-wise comparator for a class b97bd4f713 2010-11-23 kinaba: 8de5b49cdf 2010-11-09 kinaba: /*mixin*/ 8de5b49cdf 2010-11-09 kinaba: template SimpleCompare() 8de5b49cdf 2010-11-09 kinaba: { 38fcc662be 2010-11-10 kinaba: override bool opEquals(Object rhs_) const /// member-by-member equality 8de5b49cdf 2010-11-09 kinaba: { 8de5b49cdf 2010-11-09 kinaba: if( auto rhs = cast(typeof(this))rhs_ ) 8de5b49cdf 2010-11-09 kinaba: { 8de5b49cdf 2010-11-09 kinaba: foreach(i,_; this.tupleof) 515502e8d1 2010-11-20 kinaba: if( this.tupleof[i] != (cast(const)rhs).tupleof[i] ) 8de5b49cdf 2010-11-09 kinaba: return false; 8de5b49cdf 2010-11-09 kinaba: return true; 8de5b49cdf 2010-11-09 kinaba: } 8de5b49cdf 2010-11-09 kinaba: assert(false, sprintf!"Cannot compare %s with %s"(typeid(this), typeid(rhs_))); 8de5b49cdf 2010-11-09 kinaba: } 8de5b49cdf 2010-11-09 kinaba: b97bd4f713 2010-11-23 kinaba: mixin SimpleToHash; 8de5b49cdf 2010-11-09 kinaba: 38fcc662be 2010-11-10 kinaba: override int opCmp(Object rhs_) const /// member-by-member compare 8de5b49cdf 2010-11-09 kinaba: { 8de5b49cdf 2010-11-09 kinaba: if( auto rhs = cast(typeof(this))rhs_ ) 8de5b49cdf 2010-11-09 kinaba: { 8de5b49cdf 2010-11-09 kinaba: foreach(i,_; this.tupleof) 515502e8d1 2010-11-20 kinaba: if( this.tupleof[i] != (cast(const)rhs).tupleof[i] ) { 515502e8d1 2010-11-20 kinaba: auto a = (cast(SC_Unqual!(typeof(this)))this).tupleof[i]; 078444a806 2010-11-13 kinaba: auto b = rhs.tupleof[i]; 515502e8d1 2010-11-20 kinaba: return a < b ? -1 : +1; 078444a806 2010-11-13 kinaba: } 515502e8d1 2010-11-20 kinaba: // not work well for structures??????? 078444a806 2010-11-13 kinaba: // if(auto c = typeid(_).compare(&this.tupleof[i],&rhs.tupleof[i])) 078444a806 2010-11-13 kinaba: // return c; 8de5b49cdf 2010-11-09 kinaba: return 0; 8de5b49cdf 2010-11-09 kinaba: } 8de5b49cdf 2010-11-09 kinaba: assert(false, sprintf!"Cannot compare %s with %s"(typeid(this), typeid(rhs_))); 8de5b49cdf 2010-11-09 kinaba: } 8de5b49cdf 2010-11-09 kinaba: } 078444a806 2010-11-13 kinaba: 078444a806 2010-11-13 kinaba: alias std.traits.Unqual SC_Unqual; 8de5b49cdf 2010-11-09 kinaba: 8de5b49cdf 2010-11-09 kinaba: unittest 8de5b49cdf 2010-11-09 kinaba: { 8de5b49cdf 2010-11-09 kinaba: class Temp 8de5b49cdf 2010-11-09 kinaba: { 8de5b49cdf 2010-11-09 kinaba: int x; 8de5b49cdf 2010-11-09 kinaba: string y; 8de5b49cdf 2010-11-09 kinaba: mixin SimpleConstructor; 8de5b49cdf 2010-11-09 kinaba: mixin SimpleCompare; 8de5b49cdf 2010-11-09 kinaba: } 8de5b49cdf 2010-11-09 kinaba: assert_eq( new Temp(1,"foo"), new Temp(1,"foo") ); 8de5b49cdf 2010-11-09 kinaba: assert_eq( (new Temp(1,"foo")).toHash, (new Temp(1,"foo")).toHash ); 8de5b49cdf 2010-11-09 kinaba: assert_ne( new Temp(1,"foo"), new Temp(2,"foo") ); 8de5b49cdf 2010-11-09 kinaba: assert_ne( new Temp(1,"foo"), new Temp(1,"bar") ); 8de5b49cdf 2010-11-09 kinaba: assert_gt( new Temp(1,"foo"), new Temp(1,"bar") ); 8de5b49cdf 2010-11-09 kinaba: assert_lt( new Temp(1,"foo"), new Temp(2,"bar") ); 8de5b49cdf 2010-11-09 kinaba: assert_ge( new Temp(1,"foo"), new Temp(1,"foo") ); 8de5b49cdf 2010-11-09 kinaba: 8de5b49cdf 2010-11-09 kinaba: class TempDummy 8de5b49cdf 2010-11-09 kinaba: { 8de5b49cdf 2010-11-09 kinaba: int x; 8de5b49cdf 2010-11-09 kinaba: string y; 8de5b49cdf 2010-11-09 kinaba: mixin SimpleConstructor; 8de5b49cdf 2010-11-09 kinaba: mixin SimpleCompare; 8de5b49cdf 2010-11-09 kinaba: } 8de5b49cdf 2010-11-09 kinaba: assert_throw!AssertError( new Temp(1,"foo") == new TempDummy(1,"foo") ); 8de5b49cdf 2010-11-09 kinaba: assert_throw!AssertError( new Temp(1,"foo") <= new TempDummy(1,"foo") ); 8de5b49cdf 2010-11-09 kinaba: } 8de5b49cdf 2010-11-09 kinaba: 8de5b49cdf 2010-11-09 kinaba: /// Mixing-in a simple toString method 8de5b49cdf 2010-11-09 kinaba: 8de5b49cdf 2010-11-09 kinaba: /*mixin*/ 8de5b49cdf 2010-11-09 kinaba: template SimpleToString() 8de5b49cdf 2010-11-09 kinaba: { 38fcc662be 2010-11-10 kinaba: /// member-by-member toString 8de5b49cdf 2010-11-09 kinaba: override string toString() 8de5b49cdf 2010-11-09 kinaba: { 8de5b49cdf 2010-11-09 kinaba: string str = sprintf!"%s("(typeof(this).stringof); 8de5b49cdf 2010-11-09 kinaba: foreach(i,mem; this.tupleof) 8de5b49cdf 2010-11-09 kinaba: { 8de5b49cdf 2010-11-09 kinaba: if(i) str ~= ","; 8de5b49cdf 2010-11-09 kinaba: static if( is(typeof(mem) == std.bigint.BigInt) ) 8de5b49cdf 2010-11-09 kinaba: str ~= std.bigint.toDecimalString(mem); 8de5b49cdf 2010-11-09 kinaba: else 8de5b49cdf 2010-11-09 kinaba: str ~= sprintf!"%s"(mem); 8de5b49cdf 2010-11-09 kinaba: } 8de5b49cdf 2010-11-09 kinaba: return str ~ ")"; 8de5b49cdf 2010-11-09 kinaba: } 8de5b49cdf 2010-11-09 kinaba: } 8de5b49cdf 2010-11-09 kinaba: 8de5b49cdf 2010-11-09 kinaba: version(unittest) import std.bigint; 8de5b49cdf 2010-11-09 kinaba: unittest 8de5b49cdf 2010-11-09 kinaba: { 8de5b49cdf 2010-11-09 kinaba: class Temp 8de5b49cdf 2010-11-09 kinaba: { 8de5b49cdf 2010-11-09 kinaba: int x; 8de5b49cdf 2010-11-09 kinaba: string y; 8de5b49cdf 2010-11-09 kinaba: BigInt z; 8de5b49cdf 2010-11-09 kinaba: mixin SimpleConstructor; 8de5b49cdf 2010-11-09 kinaba: mixin SimpleToString; 8de5b49cdf 2010-11-09 kinaba: } 8de5b49cdf 2010-11-09 kinaba: assert_eq( (new Temp(1,"foo",BigInt(42))).toString(), "Temp(1,foo,42)" ); 8de5b49cdf 2010-11-09 kinaba: } 8de5b49cdf 2010-11-09 kinaba: 8de5b49cdf 2010-11-09 kinaba: /// Everything is in 8de5b49cdf 2010-11-09 kinaba: 8de5b49cdf 2010-11-09 kinaba: /*mixin*/ 8de5b49cdf 2010-11-09 kinaba: template SimpleClass() 8de5b49cdf 2010-11-09 kinaba: { 8de5b49cdf 2010-11-09 kinaba: mixin SimpleConstructor; 8de5b49cdf 2010-11-09 kinaba: mixin SimpleCompare; 8de5b49cdf 2010-11-09 kinaba: mixin SimpleToString; 1c01f44f52 2010-11-13 kinaba: } 1c01f44f52 2010-11-13 kinaba: 6ac127ddd0 2010-11-23 kinaba: /// Will be used for dynamic overload resolution pattern 1c01f44f52 2010-11-13 kinaba: 6ac127ddd0 2010-11-23 kinaba: template firstParam(T) 1c01f44f52 2010-11-13 kinaba: { 6ac127ddd0 2010-11-23 kinaba: alias ParameterTypeTuple!(T)[0] firstParam; 8de5b49cdf 2010-11-09 kinaba: }