Skip to content

Instantly share code, notes, and snippets.

@simendsjo
Created December 2, 2011 19:18
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save simendsjo/1424475 to your computer and use it in GitHub Desktop.
Save simendsjo/1424475 to your computer and use it in GitHub Desktop.
siunit
import std.traits, std.stdio, std.conv;
void main() {
auto f = feet(10);
auto m = meter(10.0); // kan fint bruke desimaltall
// en type til en annen - konvertering
auto feetMeter = f + m;
assert( feetMeter.siunit == "feet" );
assert( feetMeter >= feet(42.808) &&
feetMeter <= feet(42.809) );
auto meterFeet = m + f;
assert( meterFeet.siunit == "meter" );
assert( meterFeet >= meter(13.0475) &&
meterFeet <= meter(13.0485) );
// kan også bruke skalarer - og fint mikse floats inn i det
assert( m * 2.2 == meter(22.0) );
// eller konvertere direkte
auto f2 = meterFeet.to!"feet"();
assert( f2.siunit == "feet" );
assert( f2 >= feet(42.808) &&
f2 <= feet(42.809) );
// men kan ikke konvertere uten konverteringsfunksjoner
static assert(!__traits(compiles, m.to!"finnes ikke"()) );
// men kan ikke manipulere urelaterte typer
static assert(!__traits(compiles, feet(10) + celsius(10)) );
// kan caste til kompatible typer
double d = cast(double)m;
assert(d == 10.0);
// eller sammenlikne
assert( m == 10 );
assert( m > 9 );
assert( m < 11 );
}
auto meter(V)(V value) pure nothrow @safe {
return Value!("meter", V)(value);
}
auto feet(V)(V value) pure nothrow @safe {
return Value!("feet", V)(value);
}
auto celsius(V)(V value) pure nothrow @safe {
return Value!("celsius", V)(value);
}
auto fahrenheit(V)(V value) pure nothrow @safe {
return Value!("fahrenheit", V)(value);
}
auto SIConvert(string S, string D, T)(T value) pure nothrow @safe
if(S == "meter" && D == "feet") {
pragma(msg, "conv:meter>feet");
return value / 0.3048;
}
auto SIConvert(string S, string D, T)(T value) pure nothrow @safe
if(S == "feet" && D == "meter") {
pragma(msg, "conv:feet>meter");
return value * 0.3048;
}
auto SIConvert(string S, string D, T)(T value) pure nothrow @safe
if(S == "celsius" && D == "fahrenheit") {
return (value - 32) * (5/9);
}
auto SIConvert(string S, string D, T)(T value) pure nothrow @safe
if(S == "fahrenheit" && D == "celsius") {
return value * (9/5) + 32;
}
template isSIValue(T) {
// HACK: Sjekker kun om det har en unit verdi...
static if( is(typeof(T.siunit) : string) )
enum isSIValue = true;
else
enum isSIValue = false;
}
auto SIConvert(S, D, T)(T value) pure nothrow @safe
if(isSIValue!S && isSIValue!D) {
static if( S.siunit == D.siunit )
return value;
else {
static assert(__traits(compiles, SIConvert!(S.siunit, D.siunit, T)(value)),
"Cannot convert value of type "~T.stringof~
" from "~S.siunit~" to "~D.siunit);
return SIConvert!(S.siunit, D.siunit, T)(value);
}
}
struct Value(string SIUnit, V) if(isNumeric!V) {
enum siunit = SIUnit;
immutable V value;
this(V)(V value) pure nothrow @safe {
this.value = value;
}
auto opBinary(string op, RHS)(RHS r) const nothrow pure @safe
if(isSIValue!RHS) {
auto converted = SIConvert!(RHS, typeof(this))(r.value);
mixin("auto newval = value "~op~" converted;");
return Value!(siunit, typeof(newval))(newval);
}
auto opBinary(string op, RHS)(const RHS r) const nothrow pure @safe
if(isNumeric!RHS) {
mixin("auto val = value "~op~" r;");
return Value!(siunit, typeof(val))(val);
}
auto to(string unit)() {
auto val = SIConvert!(siunit, unit, typeof(value))(value);
return Value!(unit, typeof(val))(val);
}
T opCast(T)() const pure nothrow @safe
if(is(typeof(value) : T)) {
return cast(T)value;
}
bool opEquals(T)(ref const T o) const pure nothrow @safe {
return o.siunit == siunit && o.value == value;
}
int opCmp(T)(ref const T v) const pure nothrow @safe
if(isSIValue!T) {
static assert(T.siunit == siunit, "Cannot compare "~siunit~" to "~T.siunit~
". Try converting the value first");
return value < v ? -1 : (value > v ? 1 : 0);
}
int opCmp(T)(T o) const pure nothrow @safe
if(isNumeric!T) {
return value < o ? -1 : (value > o ? 1 : 0);
}
string toString() const @trusted {
return .to!string(value)~" "~siunit;
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment