1 /*
2  * Licensed to the Apache Software Foundation (ASF) under one
3  * or more contributor license agreements. See the NOTICE file
4  * distributed with this work for additional information
5  * regarding copyright ownership. The ASF licenses this file
6  * to you under the Apache License, Version 2.0 (the
7  * "License"); you may not use this file except in compliance
8  * with the License. You may obtain a copy of the License at
9  *
10  *   http://www.apache.org/licenses/LICENSE-2.0
11  *
12  * Unless required by applicable law or agreed to in writing,
13  * software distributed under the License is distributed on an
14  * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15  * KIND, either express or implied. See the License for the
16  * specific language governing permissions and limitations
17  * under the License.
18  */
19 
20 module thrift.internal.ctfe;
21 
22 import std.conv : to;
23 import std.traits;
24 
25 /*
26  * Simple eager join() for strings, std.algorithm.join isn't CTFEable yet.
27  */
28 string ctfeJoin(string[] strings, string separator = ", ") {
29   string result;
30   if (strings.length > 0) {
31     result ~= strings[0];
foreach(s;strings[1..$])32     foreach (s; strings[1..$]) {
33       result ~= separator ~ s;
34     }
35   }
36   return result;
37 }
38 
39 /*
40  * A very primitive to!string() implementation for floating point numbers that
41  * is evaluatable at compile time.
42  *
43  * There is a wealth of problems associated with the algorithm used (e.g. 5.0
44  * prints as 4.999…, incorrect rounding, etc.), but a better alternative should
45  * be included with the D standard library instead of implementing it here.
46  */
47 string ctfeToString(T)(T val) if (isFloatingPoint!T) {
48   if (val is T.nan) return "nan";
49   if (val is T.infinity) return "inf";
50   if (val is -T.infinity) return "-inf";
51   if (val is 0.0) return "0";
52   if (val is -0.0) return "-0";
53 
54   auto b = val;
55 
56   string result;
57   if (b < 0) {
58     result ~= '-';
59     b *= -1;
60   }
61 
62   short magnitude;
63   while (b >= 10) {
64     ++magnitude;
65     b /= 10;
66   }
67   while (b < 1) {
68     --magnitude;
69     b *= 10;
70   }
71 
72   foreach (i; 0 .. T.dig) {
73     if (i == 1) result ~= '.';
74 
75     auto first = cast(ubyte)b;
76     result ~= to!string(first);
77 
78     b -= first;
79     import std.math;
80     if (b < pow(10.0, i - T.dig)) break;
81     b *= 10;
82   }
83 
84   if (magnitude != 0) result ~= "e" ~ to!string(magnitude);
85   return result;
86 }
87 
88 unittest {
89   import std.algorithm;
90   static assert(ctfeToString(double.infinity) == "inf");
91   static assert(ctfeToString(-double.infinity) == "-inf");
92   static assert(ctfeToString(double.nan) == "nan");
93   static assert(ctfeToString(0.0) == "0");
94   static assert(ctfeToString(-0.0) == "-0");
95   static assert(ctfeToString(2.5) == "2.5");
96   static assert(ctfeToString(3.1415).startsWith("3.141"));
97   static assert(ctfeToString(2e-200) == "2e-200");
98 }
99