1 /// High-level wrappers for C-conversion functions.
2 module nxt.cconv;
3 
4 /// Returns: `value` as a `string`.
5 void toStringInSink(const double value,
6                     scope void delegate(scope const(char)[]) @safe sink,
7                     uint digitCount = 5)
8     @trusted
9 {
10     static immutable digitCountMax = 61;
11     assert(digitCount < digitCountMax);
12     char[3 + digitCountMax] buffer; // (sign + dot + null) and digits
13     gcvt(value, digitCount, buffer.ptr);
14     import core.stdc..string : cstrlen = strlen;
15     sink(buffer[0 .. cstrlen(buffer.ptr)]); // TODO avoid
16 }
17 
18 /// Returns: `value` as a `string`.
19 string toString(const double value,
20                 uint digitCount = 30)
21     @trusted pure nothrow
22 {
23     immutable length = 3 + digitCount; // (sign + dot + null) and digits
24     auto buffer = new char[length];
25     gcvt(value, digitCount, buffer.ptr);
26     import core.stdc..string : cstrlen = strlen;
27     return buffer[0 .. cstrlen(buffer.ptr)]; // TODO avoid
28 }
29 
30 ///
31 @safe pure nothrow unittest
32 {
33     assert(0.0.toString(1) == `0`);
34     assert(0.1.toString(2) == `0.1`);
35 
36     assert((-1.0).toString(1) == `-1`);
37     assert((-1.0).toString(2) == `-1`);
38     assert((-1.0).toString(3) == `-1`);
39 
40     assert(3.14.toString(3) == `3.14`);
41     assert(3.141.toString(1) == `3`);
42     assert(3.141.toString(2) == `3.1`);
43     assert(3.141.toString(3) == `3.14`);
44     assert(3.141.toString(4) == `3.141`);
45     assert(3.141.toString(5) == `3.141`);
46 
47     assert(1234567.123456789123456789.toString(7) == `1234567`);
48     assert(1234567.123456789123456789.toString(8) == `1234567.1`);
49     assert(1234567.123456789123456789.toString(9) == `1234567.12`);
50     assert(1234567.123456789123456789.toString(20) == `1234567.1234567892`);
51 }
52 
53 private extern(C) pragma(inline, false)
54 {
55     pure nothrow @nogc:
56     char *gcvt(double number, int ndigit, char *buf);
57 }