1 /**
2  * Type generic standard math functions and constants.
3  */
4 module bettercmath.cmath;
5 
6 import cmath = core.stdc.math;
7 import dmath = std.math;
8 import std.meta : AliasSeq;
9 
10 import bettercmath.misc : FloatType;
11 
12 private enum functions = AliasSeq!(
13     "acos",
14     "asin",
15     "atan",
16     "atan2",
17     "cos",
18     "sin",
19     "tan",
20     "acosh",
21     "asinh",
22     "atanh",
23     "cosh",
24     "sinh",
25     "tanh",
26     "exp",
27     "exp2",
28     "expm1",
29     "frexp",
30     "ilogb",
31     "ldexp",
32     "log",
33     "log10",
34     "log1p",
35     "log2",
36     "logb",
37     "modf",
38     "scalbn",
39     "scalbln",
40     "cbrt",
41     "fabs",
42     "hypot",
43     "pow",
44     "sqrt",
45     "erf",
46     "erfc",
47     "lgamma",
48     "tgamma",
49     "ceil",
50     "floor",
51     "nearbyint",
52     "rint",
53     "lrint",
54     "llrint",
55     "round",
56     "lround",
57     "llround",
58     "trunc",
59     "fmod",
60     "remainder",
61     "remquo",
62     "copysign",
63     "nan",
64     "nextafter",
65     "nexttoward",
66     "fdim",
67     "fmax",
68     "fmin",
69     "fma",
70 );
71 
72 static foreach (f; functions)
73 {
74     mixin(q{alias } ~ f ~ q{ = MathFunc!} ~ "\"" ~ f ~ "\".opCall;");
75 }
76 
77 private enum constants = AliasSeq!(
78     "E", 
79     "PI", 
80     "PI_2", 
81     "PI_4", 
82     "M_1_PI", 
83     "M_2_PI", 
84     "M_2_SQRTPI", 
85     "LN10", 
86     "LN2", 
87     "LOG2", 
88     "LOG2E", 
89     "LOG2T", 
90     "LOG10E", 
91     "SQRT2", 
92     "SQRT1_2",
93 );
94 
95 static foreach (c; constants)
96 {
97     mixin(q{alias } ~ c ~ q{ = MathConst!} ~ "\"" ~ c ~ "\";");
98 }
99 
100 // Private helpers for templated math function calls
101 private string cfuncname(T : double, string f)()
102 {
103     return f;
104 }
105 private string cfuncname(T : real, string f)()
106 {
107     return f ~ "l";
108 }
109 private string cfuncname(T : float, string f)()
110 {
111     return f ~ "f";
112 }
113 private string cfuncname(T : long, string f)()
114 {
115     return f ~ "f";
116 }
117 
118 /**
119  * Template wrapper for standard library math functions.
120  * 
121  * On CTFE, calls the D runtime math (std.math) functions.
122  * On runtime, calls the right variant of the C runtime math (core.stdc.math) functions.
123  */
124 template MathFunc(string f)
125 {
126     template opCall(T, Args...)
127     {
128         import std.traits : ReturnType;
129         private alias dfunc = __traits(getMember, dmath, f);
130         private alias cfunc = __traits(getMember, cmath, cfuncname!(T, f)());
131 
132         nothrow @nogc ReturnType!cfunc opCall(T arg1, Args args)
133         {
134             if (__ctfe)
135             {
136                 // Use D functions on CTFE
137                 return dfunc(cast(FloatType!T) arg1, args);
138             }
139             else
140             {
141                 // Use the appropriate C function on runtime
142                 return cfunc(arg1, args);
143             }
144         }
145     }
146 }
147 
148 /// Template wrapper for typed versions of the standard library math constants.
149 private template MathConst(string c)
150 {
151     private alias dconst = __traits(getMember, dmath, c);
152     enum MathConst(T = real) = cast(FloatType!T) dconst;
153 }