Artifact Content
Not logged in

Artifact 00969146488cc3dce1f70bcf1347a12b65d2dd43


     1  /**
     2   * Authors: k.inaba
     3   * License: NYSL 0.9982 http://www.kmonos.net/nysl/
     4   *
     5   * Common tricks and utilities for programming in D.
     6   */
     7  module tricks.tricks;
     8  import tricks.test;
     9  import core.exception;
    10  import std.array  : appender;
    11  import std.format : formattedWrite;
    12  import std.traits;
    13  import std.typetuple;
    14  
    15  /// Simple Wrapper for std.format.doFormat
    16  
    17  string sprintf(string fmt, T...)(T params)
    18  {
    19  	auto writer = appender!string();
    20  	formattedWrite(writer, fmt, params);
    21  	return writer.data;
    22  }
    23  
    24  unittest
    25  {
    26  	assert_eq( sprintf!"%s == %04d"("1+2", 3), "1+2 == 0003" );
    27  	assert_eq( sprintf!"%2$s == %1$s"("1+2", 5, 8), "5 == 1+2" );
    28  	assert_throw!Error( sprintf!"%s%s"(1) );
    29  }
    30  
    31  /// Create an exception with automatically completed filename and lineno information
    32  
    33  ExceptionType genex(ExceptionType, string fn=__FILE__, int ln=__LINE__, T...)(T params)
    34  {
    35  	static if( T.length > 0 && is(T[$-1] : Throwable) )
    36  		return new ExceptionType(params[0..$-1], fn, ln, params[$-1]);
    37  	else
    38  		return new ExceptionType(params, fn, ln);
    39  }
    40  
    41  unittest
    42  {
    43  	assert_ne( genex!Exception("msg").file, "" );
    44  	assert_ne( genex!Exception("msg").line, 0 );
    45  	assert_ne( genex!Exception("msg",new Exception("bar")).next, Exception.init );
    46  }
    47  
    48  /// Mixing-in the bean constructor for a class
    49  
    50  /*mixin*/
    51  template SimpleConstructor()
    52  {
    53  	/// member-by-member constructor
    54  	static if( is(typeof(super) == Object) || super.tupleof.length==0 )
    55  		this( typeof(this.tupleof) params )
    56  		{
    57  			static if(this.tupleof.length>0)
    58  				this.tupleof = params;
    59  		}
    60  	else
    61  		this( typeof(super.tupleof) ps, typeof(this.tupleof) params )
    62  		{
    63  			// including (only) the direct super class members
    64  			// may not always be a desirable choice, but should work for many cases
    65  			super(ps);
    66  			static if(this.tupleof.length>0)
    67  				this.tupleof = params;
    68  		}
    69  }
    70  
    71  unittest
    72  {
    73  	class Temp
    74  	{
    75  		int x;
    76  		string y;
    77  		mixin SimpleConstructor;
    78  	}
    79  	assert_eq( (new Temp(1,"foo")).x, 1 );
    80  	assert_eq( (new Temp(1,"foo")).y, "foo" );
    81  	assert( !__traits(compiles, new Temp) );
    82  	assert( !__traits(compiles, new Temp(1)) );
    83  	assert( !__traits(compiles, new Temp("foo",1)) );
    84  
    85  	class Tomp : Temp
    86  	{
    87  		real z;
    88  		mixin SimpleConstructor;
    89  	}
    90  	assert_eq( (new Tomp(1,"foo",2.5)).x, 1 );
    91  	assert_eq( (new Tomp(1,"foo",2.5)).y, "foo" );
    92  	assert_eq( (new Tomp(1,"foo",2.5)).z, 2.5 );
    93  	assert( !__traits(compiles, new Tomp(3.14)) );
    94  
    95  	// shiyo- desu. Don't use in this way.
    96  	//   Tamp tries to call new Tomp(real) (because it only sees Tomp's members),
    97  	//   but it fails because Tomp takes (int,string,real).
    98  	assert( !__traits(compiles, {
    99  		class Tamp : Tomp { mixin SimpleConstructor; }
   100  	}) );
   101  }
   102  
   103  hash_t structuralHash(T)(T x)
   104  {
   105  	alias SC_Unqual!(T) UCT;
   106  
   107  	static if(is(UCT == class))
   108  		return (cast(UCT)x).toHash();
   109  	else
   110  	static if(SC_HasGoodHash!(UCT))
   111  		{ return typeid(UCT).getHash(&x); }
   112  	else
   113  	static if(is(UCT T == T[]))
   114  		{ hash_t h; foreach(e; x) h+=structuralHash(e); return h; }
   115  	else
   116  	static if(is(UCT == struct))
   117  		static if(__traits(compiles, std.bigint.BigInt))
   118  			static if(is(UCT == std.bigint.BigInt))
   119  				return cast(hash_t) x.toInt();
   120  			else
   121  				static assert(false, "should not use struct.toHash");
   122  		else
   123  			static assert(false, "should not use struct.toHash");
   124  	else
   125  		static assert(false, "nonhashable datatype "~UCT.stringof);
   126  }
   127  
   128  alias std.traits.Unqual SC_Unqual;
   129  
   130  template SC_HasGoodHash(T)
   131  {
   132  	enum SC_HasGoodHash =
   133  		is(T : bool) || isNumeric!(T) || isSomeString!(T) || isSomeChar!(T) || isPointer!(T);
   134  }
   135  
   136  /// Mixing-in the MOST-DERIVED-member-wise comparator for a class
   137  /// BE SURE THAT THIS IS CONSISTENT WITH opCmp and opEquals
   138  
   139  template SimpleToHash()
   140  {
   141  	override hash_t toHash() const /// member-by-member hash
   142  	{
   143  		hash_t h = 0;
   144  		foreach(mem; this.tupleof)
   145  			h += structuralHash(mem);
   146  		return h;
   147  	}
   148  }
   149  
   150  /// Mixing-in the MOST-DERIVED-member-wise comparator for a class
   151  
   152  template SimpleCompareWithoutToHash()
   153  {
   154  	override bool opEquals(Object rhs) const /// member-by-member equality
   155  	{
   156  		return opCmp(rhs) == 0;
   157  	}
   158  
   159  	override int opCmp(Object rhs_) const /// member-by-member compare
   160  	{
   161  		if( rhs_ is null )
   162  			return -1;
   163  		if( auto rhs = cast(typeof(this))rhs_ )
   164  		{
   165  			foreach(i,_; this.tupleof)
   166  			{
   167  				static if(is(typeof(_) == struct))
   168  					auto c = (cast(SC_Unqual!(typeof(_)))this.tupleof[i]).opCmp(rhs.tupleof[i]);
   169  				else
   170  					auto c = typeid(_).compare(&this.tupleof[i],&rhs.tupleof[i]);
   171  				if(c)
   172  					return c;
   173  			}
   174  			return 0;
   175  		}
   176  		return typeid(this).opCmp(typeid(rhs_));
   177  	}
   178  }
   179  
   180  /// Mixing-in the MOST-DERIVED-member-wise comparator for a class
   181  
   182  /*mixin*/
   183  template SimpleCompare()
   184  {
   185  	mixin SimpleToHash;
   186  	mixin SimpleCompareWithoutToHash;
   187  }
   188  
   189  unittest
   190  {
   191  	class Temp
   192  	{
   193  		int x;
   194  		string y;
   195  		mixin SimpleConstructor;
   196  		mixin SimpleCompare;
   197  	}
   198  	assert_eq( new Temp(1,"foo"), new Temp(1,"foo") );
   199  	assert_eq( (new Temp(1,"foo")).toHash, (new Temp(1,"foo")).toHash );
   200  	assert_ne( new Temp(1,"foo"), new Temp(2,"foo") );
   201  	assert_ne( new Temp(1,"foo"), new Temp(1,"bar") );
   202  	assert_gt( new Temp(1,"foo"), new Temp(1,"bar") );
   203  	assert_lt( new Temp(1,"foo"), new Temp(2,"bar") );
   204  	assert_ge( new Temp(1,"foo"), new Temp(1,"foo") );
   205  
   206  	class TempDummy
   207  	{
   208  		int x;
   209  		string y;
   210  		mixin SimpleConstructor;
   211  		mixin SimpleCompare;
   212  	}
   213  	assert_ne( new Temp(1,"foo"), new TempDummy(1,"foo") );
   214  	assert_nothrow( new Temp(1,"foo") <= new TempDummy(1,"foo") );
   215  }
   216  
   217  /// Mixing-in a simple toString method
   218  
   219  /*mixin*/
   220  template SimpleToString()
   221  {
   222  	/// member-by-member toString
   223  	override string toString()
   224  	{
   225  		string str = sprintf!"%s("(typeof(this).stringof);
   226  		foreach(i,mem; this.tupleof)
   227  		{
   228  			if(i) str ~= ",";
   229  			static if( is(typeof(mem) == std.bigint.BigInt) )
   230  				str ~= std.bigint.toDecimalString(mem);
   231  			else
   232  				str ~= sprintf!"%s"(mem);
   233  		}
   234  		return str ~ ")";
   235  	}
   236  }
   237  
   238  version(unittest) import std.bigint;
   239  unittest
   240  {
   241  	class Temp
   242  	{
   243  		int x;
   244  		string y;
   245  		BigInt z;
   246  		mixin SimpleConstructor;
   247  		mixin SimpleToString;
   248  	}
   249  	assert_eq( (new Temp(1,"foo",BigInt(42))).toString(), "Temp(1,foo,42)" );
   250  }
   251  
   252  /// Everything is in
   253  
   254  /*mixin*/
   255  template SimpleClass()
   256  {
   257  	mixin SimpleConstructor;
   258  	mixin SimpleCompare;
   259  	mixin SimpleToString;
   260  }
   261  
   262  /// Utility
   263  
   264  template firstParam(T)
   265  {
   266  	alias ParameterTypeTuple!(T)[0] firstParam;
   267  }