1 module toml_foolery.decode.types.floating_point;
2 
3 import std.algorithm : filter;
4 import std.conv : to;
5 
6 version (unittest)
7 {
8     import std.math : isNaN;
9     import dshould;
10 }
11 
12 
13 package(toml_foolery.decode) real parseTomlFloat(string value)
14 {
15     if (value[$-3 .. $] == "inf")
16     {
17         if (value[0] == '-')
18         {
19             return -real.infinity;
20         }
21 
22         return real.infinity;
23     }
24 
25     return value.filter!(e => e != '_').to!real;
26 }
27 
28 @("Fractional — Basic")
29 unittest
30 {
31     parseTomlFloat("3.14159").should.equal.approximately(3.14159, error = 1.0e-05);
32 }
33 
34 @("Fractional — With +")
35 unittest
36 {
37     parseTomlFloat("+1.0").should.equal.approximately(1.0, error = 1.0e-05);
38 }
39 
40 @("Fractional — Negative")
41 unittest
42 {
43     parseTomlFloat("-1.0").should.equal.approximately(-1.0, error = 1.0e-05);
44 }
45 
46 @("Exponential — Basic")
47 unittest
48 {
49     parseTomlFloat("2e7").should.equal.approximately(20_000_000.0, error = 1.0e-05);
50 }
51 
52 @("Exponential — With +")
53 unittest
54 {
55     parseTomlFloat("3e+05").should.equal.approximately(300_000.0, error = 1.0e-05);
56 }
57 
58 @("Exponential — Negative base/exponent/both")
59 unittest
60 {
61     parseTomlFloat("-2e7").should.equal.approximately(-20_000_000.0, error = 1.0e-05);
62     parseTomlFloat("2e-7").should.equal.approximately(0.0_000_002, error = 1.0e-05);
63     parseTomlFloat("-2e-7").should.equal.approximately(-0.0_000_002, error = 1.0e-05);
64 }
65 
66 @("Fraxponential")
67 unittest
68 {
69     parseTomlFloat("-3.14159e-03").should.equal.approximately(-0.003_141_59, error = 1.0e-05);
70 }
71 
72 @("NaN")
73 unittest
74 {
75     assert(parseTomlFloat("nan").isNaN, "Expected NaN, received: " ~ parseTomlFloat("nan").to!string);
76     assert(parseTomlFloat("+nan").isNaN, "Expected NaN, received: " ~ parseTomlFloat("+nan").to!string);
77     assert(parseTomlFloat("-nan").isNaN, "Expected NaN, received: " ~ parseTomlFloat("-nan").to!string);
78 }
79 
80 @("Infinity")
81 unittest
82 {
83     parseTomlFloat("inf").should.equal(real.infinity);
84     parseTomlFloat("+inf").should.equal(real.infinity);
85     parseTomlFloat("-inf").should.equal(-real.infinity);
86 }
87 
88 @("Underscores")
89 unittest
90 {
91     parseTomlFloat("-3.1_41_59e-0_3").should.equal.approximately(-0.003_141_59, error = 1.0e-05);
92 }