1 /** 2 Functions that transform strings into values or vice versa. 3 4 Copyright: © 2019 Arne Ludwig <arne.ludwig@posteo.de> 5 License: Subject to the terms of the MIT license, as written in the 6 included LICENSE file. 7 Authors: Arne Ludwig <arne.ludwig@posteo.de> 8 */ 9 module darg_plus..string; 10 11 12 /** 13 Parses a range in form `x..y` into a 2-element array. 14 15 Params: 16 dest = Range limits are written to the aliased static array. 17 DestType = Allocate and return a static array of this type. 18 msg = Error message in case of failure. 19 rangeString = The string to be parsed. The expected format is `x..y`. 20 */ 21 void parseRange(alias dest, string msg = "ill-formatted range")(in string rangeString) pure 22 if (isStaticArray!(typeof(dest)) && dest.length == 2) 23 { 24 try 25 { 26 rangeString[].formattedRead!"%d..%d"(dest[0], dest[1]); 27 } 28 catch (Exception e) 29 { 30 throw new CLIException(msg); 31 } 32 } 33 34 /// ditto 35 DestType parseRange(DestType, string msg = "ill-formatted range")(in string rangeString) pure 36 if (isStaticArray!DestType && DestType.init.length == 2) 37 { 38 try 39 { 40 DestType dest; 41 42 rangeString[].formattedRead!"%d..%d"(dest[0], dest[1]); 43 44 return dest; 45 } 46 catch (Exception e) 47 { 48 throw new CLIException(msg); 49 } 50 } 51 52 import std.traits : isFloatingPoint; 53 54 /** 55 Convert a floating point number to a base-10 string at compile time. 56 This function is very crude and will not work in many cases! 57 */ 58 string toString(Float)(in Float value, in uint precision) pure nothrow 59 if (isFloatingPoint!Float) 60 { 61 import std.conv : to; 62 import std.math : 63 ceil, 64 floor, 65 isInfinity, 66 isNaN, 67 round, 68 sgn; 69 70 if (value.isNaN) 71 return "nan"; 72 else if (value.isInfinity) 73 return value > 0 ? "inf" : "-inf"; 74 75 if (precision == 0) 76 { 77 auto intPart = cast(long) round(value); 78 79 return intPart.to!string; 80 } 81 else 82 { 83 auto intPart = cast(long) (value > 0 ? floor(value) : ceil(value)); 84 auto fraction = sgn(value) * (value - intPart); 85 assert(fraction >= 0, "fractional part of value should be non-negative"); 86 auto fracPart = cast(ulong) round(10^^precision * fraction); 87 88 return intPart.to!string ~ "." ~ fracPart.to!string; 89 } 90 } 91 92 /// 93 unittest 94 { 95 enum x = 42.0; 96 enum y = -13.37f; 97 enum z = 0.9; 98 99 static assert(float.nan.toString(0) == "nan"); 100 static assert(double.infinity.toString(0) == "inf"); 101 static assert((-double.infinity).toString(0) == "-inf"); 102 static assert(x.toString(0) == "42"); 103 static assert(x.toString(1) == "42.0"); 104 static assert(y.toString(2) == "-13.37"); 105 static assert(y.toString(1) == "-13.4"); 106 static assert(y.toString(0) == "-13"); 107 static assert(z.toString(1) == "0.9"); 108 static assert(z.toString(0) == "1"); 109 }