Artifact Content
Not logged in

Artifact d70e48b147acc2422a34d61271fc72b9d65b1aa4


     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 std.array      : appender;
    10  import std.format     : formattedWrite;
    11  import core.exception : AssertError;
    12  
    13  /// Simple Wrapper for std.format.doFormat
    14  
    15  string sprintf(string fmt, T...)(T params)
    16  {
    17  	auto writer = appender!string();
    18  	formattedWrite(writer, fmt, params);
    19  	return writer.data;
    20  }
    21  
    22  unittest
    23  {
    24  	assert_eq( sprintf!"%s == %04d"("1+2", 3), "1+2 == 0003" );
    25  	assert_eq( sprintf!"%2$s == %1$s"("1+2", 5, 8), "5 == 1+2" );
    26  	assert_throw!Error( sprintf!"%s%s"(1) );
    27  }
    28  
    29  /// Create an exception with automatically completed filename and lineno information
    30  
    31  ExceptionType genex(ExceptionType, string fn=__FILE__, int ln=__LINE__, T...)(T params)
    32  {
    33  	static if( T.length > 0 && is(T[$-1] : Throwable) )
    34  		return new ExceptionType(params[0..$-1], fn, ln, params[$-1]);
    35  	else
    36  		return new ExceptionType(params, fn, ln);
    37  }
    38  
    39  unittest
    40  {
    41  	assert_ne( genex!Exception("msg").file, "" );
    42  	assert_ne( genex!Exception("msg").line, 0 );
    43  	assert_ne( genex!Exception("msg",new Exception("bar")).next, Exception.init );
    44  }
    45  
    46  /// Mixing-in the bean constructor for a class
    47  
    48  /*mixin*/
    49  template SimpleConstructor()
    50  {
    51  	/// member-by-member constructor
    52  	static if( is(typeof(super) == Object) || super.tupleof.length==0 )
    53  		this( typeof(this.tupleof) params )
    54  		{
    55  			static if(this.tupleof.length>0)
    56  				this.tupleof = params;
    57  		}
    58  	else
    59  		this( typeof(super.tupleof) ps, typeof(this.tupleof) params )
    60  		{
    61  			// including (only) the direct super class members
    62  			// may not always be a desirable choice, but should work for many cases
    63  			super(ps);
    64  			static if(this.tupleof.length>0)
    65  				this.tupleof = params;
    66  		}
    67  }
    68  
    69  unittest
    70  {
    71  	class Temp
    72  	{
    73  		int x;
    74  		string y;
    75  		mixin SimpleConstructor;
    76  	}
    77  	assert_eq( (new Temp(1,"foo")).x, 1 );
    78  	assert_eq( (new Temp(1,"foo")).y, "foo" );
    79  	assert( !__traits(compiles, new Temp) );
    80  	assert( !__traits(compiles, new Temp(1)) );
    81  	assert( !__traits(compiles, new Temp("foo",1)) );
    82  
    83  	class Tomp : Temp
    84  	{
    85  		real z;
    86  		mixin SimpleConstructor;
    87  	}
    88  	assert_eq( (new Tomp(1,"foo",2.5)).x, 1 );
    89  	assert_eq( (new Tomp(1,"foo",2.5)).y, "foo" );
    90  	assert_eq( (new Tomp(1,"foo",2.5)).z, 2.5 );
    91  	assert( !__traits(compiles, new Tomp(3.14)) );
    92  
    93  	// shiyo- desu. Don't use in this way.
    94  	//   Tamp tries to call new Tomp(real) (because it only sees Tomp's members),
    95  	//   but it fails because Tomp takes (int,string,real).
    96  	assert( !__traits(compiles, {
    97  		class Tamp : Tomp { mixin SimpleConstructor; }
    98  	}) );
    99  }
   100  
   101  /// Mixing-in the MOST-DERIVED-member-wise comparator for a class
   102  
   103  /*mixin*/
   104  template SimpleCompare()
   105  {
   106  	override bool opEquals(Object rhs_) const /// member-by-member equality
   107  	{
   108  		if( auto rhs = cast(typeof(this))rhs_ )
   109  		{
   110  			foreach(i,_; this.tupleof)
   111  				if( this.tupleof[i] != rhs.tupleof[i] )
   112  					return false;
   113  			return true;
   114  		}
   115  		assert(false, sprintf!"Cannot compare %s with %s"(typeid(this), typeid(rhs_)));
   116  	}
   117  
   118  	override hash_t toHash() const /// member-by-member hash
   119  	{
   120  		hash_t h = 0;
   121  		foreach(mem; this.tupleof)
   122  			h += typeid(mem).getHash(&mem);
   123  		return h;
   124  	}
   125  
   126  	override int opCmp(Object rhs_) const /// member-by-member compare
   127  	{
   128  		if( auto rhs = cast(typeof(this))rhs_ )
   129  		{
   130  			foreach(i,_; this.tupleof)
   131  				if(auto c = typeid(_).compare(&this.tupleof[i],&rhs.tupleof[i]))
   132  					return c;
   133  			return 0;
   134  		}
   135  		assert(false, sprintf!"Cannot compare %s with %s"(typeid(this), typeid(rhs_)));
   136  	}
   137  }
   138  
   139  unittest
   140  {
   141  	class Temp
   142  	{
   143  		int x;
   144  		string y;
   145  		mixin SimpleConstructor;
   146  		mixin SimpleCompare;
   147  	}
   148  	assert_eq( new Temp(1,"foo"), new Temp(1,"foo") );
   149  	assert_eq( (new Temp(1,"foo")).toHash, (new Temp(1,"foo")).toHash );
   150  	assert_ne( new Temp(1,"foo"), new Temp(2,"foo") );
   151  	assert_ne( new Temp(1,"foo"), new Temp(1,"bar") );
   152  	assert_gt( new Temp(1,"foo"), new Temp(1,"bar") );
   153  	assert_lt( new Temp(1,"foo"), new Temp(2,"bar") );
   154  	assert_ge( new Temp(1,"foo"), new Temp(1,"foo") );
   155  
   156  	class TempDummy
   157  	{
   158  		int x;
   159  		string y;
   160  		mixin SimpleConstructor;
   161  		mixin SimpleCompare;
   162  	}
   163  	assert_throw!AssertError( new Temp(1,"foo") == new TempDummy(1,"foo") );
   164  	assert_throw!AssertError( new Temp(1,"foo") <= new TempDummy(1,"foo") );
   165  }
   166  
   167  /// Mixing-in a simple toString method
   168  
   169  /*mixin*/
   170  template SimpleToString()
   171  {
   172  	/// member-by-member toString
   173  	override string toString()
   174  	{
   175  		string str = sprintf!"%s("(typeof(this).stringof);
   176  		foreach(i,mem; this.tupleof)
   177  		{
   178  			if(i) str ~= ",";
   179  			static if( is(typeof(mem) == std.bigint.BigInt) )
   180  				str ~= std.bigint.toDecimalString(mem);
   181  			else
   182  				str ~= sprintf!"%s"(mem);
   183  		}
   184  		return str ~ ")";
   185  	}
   186  }
   187  
   188  version(unittest) import std.bigint;
   189  unittest
   190  {
   191  	class Temp
   192  	{
   193  		int x;
   194  		string y;
   195  		BigInt z;
   196  		mixin SimpleConstructor;
   197  		mixin SimpleToString;
   198  	}
   199  	assert_eq( (new Temp(1,"foo",BigInt(42))).toString(), "Temp(1,foo,42)" );
   200  }
   201  
   202  /// Everything is in
   203  
   204  /*mixin*/
   205  template SimpleClass()
   206  {
   207  	mixin SimpleConstructor;
   208  	mixin SimpleCompare;
   209  	mixin SimpleToString;
   210  }