challenge: implement the max function
Sean Kelly
sean at f4.ca
Mon Jan 22 11:51:20 PST 2007
Andrei Alexandrescu (See Website For Email) wrote:
> Here's a simple challenge: implement the max function. Requirements:
>
> a) generic
> b) efficient
> c) preserve lvalueness when possible such that one can write e.g.
>
> max(arr[0], arr[1]) *= 0.9;
This is the largest stumbling block. The rest could be handled with
template code, though it may be a fairly verbose.
> d) should accept two or more arguments
> e) should return the "smartest" type, e.g. max of an unsigned int and
> unsigned long should return unsigned long
> f) short and easy to understand
>
> I don't think it's possible to implement the function to the spec in
> current D, so designs are allowed to invent new features, as long as
> they define them thoroughly.
Reference return types notwithstanding, I took an initial stab at this a
few months ago, as outlined in D.learn "max() in phobos?" (11/6/2006) on
digitalmars.D.learn:
http://www.digitalmars.com/pnews/read.php?server=news.digitalmars.com&group=digitalmars.D.learn&artnum=5152
I got distracted and never finished with it, but at the time I was
experimenting with reducing the template code by using typeof( a + b )
as the return type when a and b are concrete values. However, this
wouldn't work if a reference type must be returned because of D's
integer promotion rules (typeof( a + b ) == int where a and b are
smaller than int). Some problems with the code:
* It doesn't handle comparison of a UDT and a concrete type. This could
be done by adding more template code, but I didn't bother with it at
the time--I was hoping for something simple and the code is already
somewhat complex.
* The casts in min/max are required to support UDT comparison because
the overload resolution mechanism can't handle complex situations. An
alternative might be to require the user to explicitly cast one of the
parameters for min/max, but to me that kind of defeats the point of
the min/max functions as a macro look-alike.
Most of the template code really belongs in a Traits module, but as it's
required for the min/max implementation I think it should be counted
when evaluating complexity :-)
--------------------------------------------------------------------------------
template isSignedIntegerType( T )
{
const bool isSignedIntegerType = is( T == byte ) ||
is( T == short ) ||
is( T == int ) ||
is( T == long )/+||
is( T == cent )+/;
}
template isUnsignedIntegerType( T )
{
const bool isUnsignedIntegerType = is( T == ubyte ) ||
is( T == ushort ) ||
is( T == uint ) ||
is( T == ulong )/+||
is( T == ucent )+/;
}
template isIntegerType( T )
{
const bool isIntegerType = isSignedIntegerType!(T) ||
isUnsignedIntegerType!(T);
}
template commonBaseTypeOf( T, U )
{
static assert( ( is( T == class ) && is( U == class ) ) ||
( is( T == interface ) && is( U == interface ) ),
"Supplied types are not siblings." );
static if( is( T : U ) )
alias U commonBaseTypeOf;
else static if( is( U : T ) )
alias T commonBaseTypeOf;
else static if( is( T == class ) )
alias Object commonBaseTypeOf;
else
static assert( false, "Interfaces have no generic parent." );
}
template bestCommonTypeOf( T, U )
{
static if( is( T == class ) || is( U == class ) ||
is( T == interface ) || is( U == interface ) )
{
alias commonBaseTypeOf!( T, U ) bestCommonTypeOf;
}
else static if( is( T : U ) && is( U : T ) )
{
static if( T.sizeof > U.sizeof )
alias T bestCommonTypeOf;
else static if( T.sizeof < U.sizeof )
alias U bestCommonTypeOf;
else static if( isUnsignedIntegerType!(T) )
alias T bestCommonTypeOf;
else
alias U bestCommonTypeOf;
}
else static if( is( U : T ) )
alias T bestCommonTypeOf;
else static if( is( T : U ) )
alias U bestCommonTypeOf;
else
static assert( false, "Unable to find common type." );
}
template min( T, U )
{
bestCommonTypeOf!(T, U) min( T t, U u )
{
alias bestCommonTypeOf!(T, U) rt;
if( cast(rt) t < cast(rt) u )
return t;
return u;
}
}
template max( T, U )
{
bestCommonTypeOf!(T, U) max( T t, U u )
{
alias bestCommonTypeOf!(T, U) rt;
if( cast(rt) t > cast(rt) u )
return t;
return u;
}
}
void main()
{
class B
{
this( int v )
{
value = v;
}
int opCmp( B rhs )
{
return value - rhs.value;
}
int opCmp( Object rhs )
{
return opCmp( cast(B) rhs );
}
private int value;
}
class C : B
{
this( int v )
{
super( v );
}
}
class D : B
{
this( int v )
{
super( v );
}
}
static assert( is( bestCommonTypeOf!( int, uint ) == uint ) );
static assert( is( bestCommonTypeOf!( uint, int ) == uint ) );
static assert( is( bestCommonTypeOf!( long, uint ) == long ) );
static assert( is( bestCommonTypeOf!( uint, long ) == long ) );
static assert( is( bestCommonTypeOf!( char, byte ) == byte ) );
static assert( is( bestCommonTypeOf!( byte, char ) == char ) );
static assert( is( bestCommonTypeOf!( byte, long ) == long ) );
static assert( is( bestCommonTypeOf!( long, byte ) == long ) );
static assert( is( bestCommonTypeOf!( long, float ) == float ) );
static assert( is( bestCommonTypeOf!( float, long ) == float ) );
static assert( is( bestCommonTypeOf!( float, real ) == real ) );
static assert( is( bestCommonTypeOf!( cfloat, creal ) == creal ) );
static assert( is( bestCommonTypeOf!( creal, cfloat ) == creal ) );
static assert( is( bestCommonTypeOf!( B, C ) == B ) );
static assert( is( bestCommonTypeOf!( C, B ) == B ) );
static assert( is( bestCommonTypeOf!( C, D ) == Object ) );
static assert( is( bestCommonTypeOf!( D, C ) == Object ) );
int ismall = 1, ibig = 2;
byte bsmall = 1, bbig = 2;
float fsmall = 1, fbig = 2;
double dsmall = 1, dbig = 2;
assert( max( ibig, ismall )==ibig );
assert( max( ismall, ibig )==ibig);
assert( min( ibig, ismall )==ismall );
assert( min( ismall, ibig )==ismall );
assert( max( fbig, fsmall )==fbig );
assert( max( fsmall, fbig )==fbig );
assert( min( fbig, fsmall )==fsmall );
assert( min( fsmall, fbig )==fsmall );
assert( min( dsmall, fbig )==dsmall );
assert( max( dsmall, fbig )==fbig );
assert( min( dbig, fsmall )==fsmall );
assert( max( dbig, fsmall )==dbig );
assert( is( typeof( min( dsmall, fbig ) ) == double ) );
assert( is( typeof( max( dsmall, fbig ) ) == double ) );
assert( is( typeof( min( dbig, fsmall ) ) == double ) );
assert( is( typeof( max( dbig, fsmall ) ) == double ) );
assert( is( typeof( min( bsmall, ibig ) ) == int ) );
assert( is( typeof( max( bsmall, ibig ) ) == int ) );
assert( is( typeof( min( bbig, ismall ) ) == int ) );
assert( is( typeof( max( bbig, ismall ) ) == int ) );
B b = new B( 1 );
C c = new C( 2 );
D d = new D( 3 );
assert( min( b, c ) == b );
assert( max( b, c ) == c );
assert( min( c, d ) == c );
assert( max( c, d ) == d );
assert( b < cast(B) c );
assert( cast(B) c > b );
/*
char a;
byte b;
struct S {} struct T {}
static assert( is( typeof( a + b ) == char ) );
auto c = a + b;
static assert( is( typeof( ubyte.init + ushort.init ) == bool ) );
*/
}
More information about the Digitalmars-d
mailing list