1 /++ 2 This module only contains a template mixin used to generate 3 SI units, prefixes and utility functions usable at compile time. 4 5 Copyright: Copyright 2013-2018, Nicolas Sicard 6 Authors: Nicolas Sicard 7 License: $(LINK www.boost.org/LICENSE_1_0.txt, Boost License 1.0) 8 Source: $(LINK https://github.com/biozic/quantities) 9 +/ 10 module quantities.compiletime.si.definitions; 11 12 /++ 13 Generates SI units, prefixes and several utility functions 14 (parsing and formatting) usable at compile time. 15 +/ 16 mixin template CompiletimeSI(N) 17 { 18 enum siSymbols = siSymbolList; 19 20 /// Predefined quantity type templates for SI quantities 21 alias Dimensionless = typeof(one); 22 alias Length = typeof(meter); 23 alias Mass = typeof(kilogram); /// ditto 24 alias Time = typeof(second); /// ditto 25 alias ElectricCurrent = typeof(ampere); /// ditto 26 alias Temperature = typeof(kelvin); /// ditto 27 alias AmountOfSubstance = typeof(mole); /// ditto 28 alias LuminousIntensity = typeof(candela); /// ditto 29 30 alias Area = typeof(square(meter)); /// ditto 31 alias Surface = Area; 32 alias Volume = typeof(cubic(meter)); /// ditto 33 alias Speed = typeof(meter/second); /// ditto 34 alias Acceleration = typeof(meter/square(second)); /// ditto 35 alias MassDensity = typeof(kilogram/cubic(meter)); /// ditto 36 alias CurrentDensity = typeof(ampere/square(meter)); /// ditto 37 alias MagneticFieldStrength = typeof(ampere/meter); /// ditto 38 alias Concentration = typeof(mole/cubic(meter)); /// ditto 39 alias MolarConcentration = Concentration; /// ditto 40 alias MassicConcentration = typeof(kilogram/cubic(meter)); /// ditto 41 alias Luminance = typeof(candela/square(meter)); /// ditto 42 alias RefractiveIndex = typeof(kilogram); /// ditto 43 44 alias Angle = typeof(radian); /// ditto 45 alias SolidAngle = typeof(steradian); /// ditto 46 alias Frequency = typeof(hertz); /// ditto 47 alias Force = typeof(newton); /// ditto 48 alias Pressure = typeof(pascal); /// ditto 49 alias Energy = typeof(joule); /// ditto 50 alias Work = Energy; /// ditto 51 alias Heat = Energy; /// ditto 52 alias Power = typeof(watt); /// ditto 53 alias ElectricCharge = typeof(coulomb); /// ditto 54 alias ElectricPotential = typeof(volt); /// ditto 55 alias Capacitance = typeof(farad); /// ditto 56 alias ElectricResistance = typeof(ohm); /// ditto 57 alias ElectricConductance = typeof(siemens); /// ditto 58 alias MagneticFlux = typeof(weber); /// ditto 59 alias MagneticFluxDensity = typeof(tesla); /// ditto 60 alias Inductance = typeof(henry); /// ditto 61 alias LuminousFlux = typeof(lumen); /// ditto 62 alias Illuminance = typeof(lux); /// ditto 63 alias CelsiusTemperature = typeof(celsius); /// ditto 64 alias Radioactivity = typeof(becquerel); /// ditto 65 alias AbsorbedDose = typeof(gray); /// ditto 66 alias DoseEquivalent = typeof(sievert); /// ditto 67 alias CatalyticActivity = typeof(katal); /// ditto 68 69 import std.traits : isSomeString; 70 71 /++ 72 Parses a string for a quantity of type Q at run time. 73 74 Params: 75 Q = the type of the returned quantity. 76 str = the string to parse. 77 +/ 78 Q parseSI(Q, S)(S str) 79 if (isSomeString!S) 80 { 81 import quantities.runtime.parsing : Parser; 82 import std.conv : parse; 83 84 enum siParser = Parser!(N, (ref S s) => parse!N(s))(siSymbols); 85 return Q(siParser.parse(str)); 86 } 87 /// 88 unittest 89 { 90 alias Time = typeof(second); 91 Time t = parseSI!Time("90 min"); 92 assert(t == 90 * minute); 93 t = parseSI!Time("h"); 94 assert(t == 1 * hour); 95 } 96 97 /++ 98 Creates a Quantity from a string at compile-time. 99 +/ 100 template si(string str) 101 { 102 import quantities.runtime.qvariant; 103 import quantities.runtime.parsing : Parser; 104 import std.conv : parse; 105 106 enum siParser = Parser!(N, (ref string s) => parse!N(s))(siSymbols); 107 enum qty = siParser.parse(str); 108 enum spec = QVariant!N(1, qty.dimensions); 109 enum si = Quantity!(N, spec)(qty); 110 } 111 /// 112 unittest 113 { 114 alias Time = typeof(second); 115 enum t = si!"90 min"; 116 static assert(is(typeof(t) == Time)); 117 static assert(si!"h" == 60 * 60 * second); 118 } 119 120 /++ 121 Formats a SI quantity according to a format string known at compile time. 122 Params: 123 fmt = The format string. Must start with a format specification 124 for the value of the quantity (a numeric type), that must be 125 followed by the symbol of a SI unit. 126 quantity = The quantity that must be formatted. 127 +/ 128 auto siFormat(string fmt, Q)(Q quantity) 129 { 130 return SIFormatter!(fmt, Q)(quantity); 131 } 132 /// 133 unittest 134 { 135 import std.conv : text; 136 137 enum speed = 12.5 * kilo(meter) / hour; 138 assert(siFormat!"%.2f m/s"(speed).text == "3.47 m/s"); 139 } 140 141 /// Ditto 142 struct SIFormatter(string fmt, Q) 143 { 144 private Q quantity; 145 146 enum unit = { 147 import std.format : FormatSpec; 148 import std.array : Appender; 149 150 auto spec = FormatSpec!char(fmt); 151 auto app = Appender!string(); 152 spec.writeUpToNextSpec(app); 153 return parseSI!Q(spec.trailing); 154 }(); 155 156 /++ 157 Create a formatter struct. 158 159 Params: 160 format = The format string. Must start with a format specification 161 for the value of the quantity (a numeric type), that must be 162 followed by the symbol of a SI unit. 163 quantity = The quantity that must be formatted. 164 +/ 165 this(Q quantity) 166 { 167 this.quantity = quantity; 168 } 169 170 /// 171 void toString(scope void delegate(const(char)[]) sink) const 172 { 173 import std.format : formattedWrite; 174 175 sink.formattedWrite!fmt(quantity.value(unit)); 176 } 177 } 178 }