/src/mozilla-central/dom/xslt/base/txDouble.cpp
Line | Count | Source (jump to first uncovered line) |
1 | | /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ |
2 | | /* This Source Code Form is subject to the terms of the Mozilla Public |
3 | | * License, v. 2.0. If a copy of the MPL was not distributed with this |
4 | | * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ |
5 | | |
6 | | #include "mozilla/FloatingPoint.h" |
7 | | |
8 | | #include "nsString.h" |
9 | | #include "txCore.h" |
10 | | #include "txXMLUtils.h" |
11 | | #include <math.h> |
12 | | #include <stdlib.h> |
13 | | #include <algorithm> |
14 | | #ifdef WIN32 |
15 | | #include <float.h> |
16 | | #endif |
17 | | #include "prdtoa.h" |
18 | | |
19 | | /* |
20 | | * Utility class for doubles |
21 | | */ |
22 | | |
23 | | /* |
24 | | * Converts the given String to a double, if the String value does not |
25 | | * represent a double, NaN will be returned |
26 | | */ |
27 | | class txStringToDouble |
28 | | { |
29 | | public: |
30 | 0 | txStringToDouble(): mState(eWhitestart), mSign(ePositive) {} |
31 | | |
32 | | void |
33 | | Parse(const nsAString& aSource) |
34 | 0 | { |
35 | 0 | if (mState == eIllegal) { |
36 | 0 | return; |
37 | 0 | } |
38 | 0 | uint32_t i = 0; |
39 | 0 | char16_t c; |
40 | 0 | auto len = aSource.Length(); |
41 | 0 | for ( ; i < len; ++i) { |
42 | 0 | c = aSource[i]; |
43 | 0 | switch (mState) { |
44 | 0 | case eWhitestart: |
45 | 0 | if (c == '-') { |
46 | 0 | mState = eDecimal; |
47 | 0 | mSign = eNegative; |
48 | 0 | } |
49 | 0 | else if (c >= '0' && c <= '9') { |
50 | 0 | mState = eDecimal; |
51 | 0 | mBuffer.Append((char)c); |
52 | 0 | } |
53 | 0 | else if (c == '.') { |
54 | 0 | mState = eMantissa; |
55 | 0 | mBuffer.Append((char)c); |
56 | 0 | } |
57 | 0 | else if (!XMLUtils::isWhitespace(c)) { |
58 | 0 | mState = eIllegal; |
59 | 0 | return; |
60 | 0 | } |
61 | 0 | break; |
62 | 0 | case eDecimal: |
63 | 0 | if (c >= '0' && c <= '9') { |
64 | 0 | mBuffer.Append((char)c); |
65 | 0 | } |
66 | 0 | else if (c == '.') { |
67 | 0 | mState = eMantissa; |
68 | 0 | mBuffer.Append((char)c); |
69 | 0 | } |
70 | 0 | else if (XMLUtils::isWhitespace(c)) { |
71 | 0 | mState = eWhiteend; |
72 | 0 | } |
73 | 0 | else { |
74 | 0 | mState = eIllegal; |
75 | 0 | return; |
76 | 0 | } |
77 | 0 | break; |
78 | 0 | case eMantissa: |
79 | 0 | if (c >= '0' && c <= '9') { |
80 | 0 | mBuffer.Append((char)c); |
81 | 0 | } |
82 | 0 | else if (XMLUtils::isWhitespace(c)) { |
83 | 0 | mState = eWhiteend; |
84 | 0 | } |
85 | 0 | else { |
86 | 0 | mState = eIllegal; |
87 | 0 | return; |
88 | 0 | } |
89 | 0 | break; |
90 | 0 | case eWhiteend: |
91 | 0 | if (!XMLUtils::isWhitespace(c)) { |
92 | 0 | mState = eIllegal; |
93 | 0 | return; |
94 | 0 | } |
95 | 0 | break; |
96 | 0 | default: |
97 | 0 | break; |
98 | 0 | } |
99 | 0 | } |
100 | 0 | } |
101 | | |
102 | | double |
103 | | getDouble() |
104 | 0 | { |
105 | 0 | if (mState == eIllegal || mBuffer.IsEmpty() || |
106 | 0 | (mBuffer.Length() == 1 && mBuffer[0] == '.')) { |
107 | 0 | return mozilla::UnspecifiedNaN<double>(); |
108 | 0 | } |
109 | 0 | return mSign*PR_strtod(mBuffer.get(), 0); |
110 | 0 | } |
111 | | private: |
112 | | nsAutoCString mBuffer; |
113 | | enum { |
114 | | eWhitestart, |
115 | | eDecimal, |
116 | | eMantissa, |
117 | | eWhiteend, |
118 | | eIllegal |
119 | | } mState; |
120 | | enum { |
121 | | eNegative = -1, |
122 | | ePositive = 1 |
123 | | } mSign; |
124 | | }; |
125 | | |
126 | | double txDouble::toDouble(const nsAString& aSrc) |
127 | 0 | { |
128 | 0 | txStringToDouble sink; |
129 | 0 | sink.Parse(aSrc); |
130 | 0 | return sink.getDouble(); |
131 | 0 | } |
132 | | |
133 | | /* |
134 | | * Converts the value of the given double to a String, and places |
135 | | * The result into the destination String. |
136 | | * @return the given dest string |
137 | | */ |
138 | | void txDouble::toString(double aValue, nsAString& aDest) |
139 | 0 | { |
140 | 0 |
|
141 | 0 | // check for special cases |
142 | 0 |
|
143 | 0 | if (mozilla::IsNaN(aValue)) { |
144 | 0 | aDest.AppendLiteral("NaN"); |
145 | 0 | return; |
146 | 0 | } |
147 | 0 | if (mozilla::IsInfinite(aValue)) { |
148 | 0 | if (aValue < 0) |
149 | 0 | aDest.Append(char16_t('-')); |
150 | 0 | aDest.AppendLiteral("Infinity"); |
151 | 0 | return; |
152 | 0 | } |
153 | 0 |
|
154 | 0 | // Mantissa length is 17, so this is plenty |
155 | 0 | const int buflen = 20; |
156 | 0 | char buf[buflen]; |
157 | 0 |
|
158 | 0 | int intDigits, sign; |
159 | 0 | char* endp; |
160 | 0 | PR_dtoa(aValue, 0, 0, &intDigits, &sign, &endp, buf, buflen - 1); |
161 | 0 |
|
162 | 0 | // compute length |
163 | 0 | int32_t length = endp - buf; |
164 | 0 | if (length > intDigits) { |
165 | 0 | // decimal point needed |
166 | 0 | ++length; |
167 | 0 | if (intDigits < 1) { |
168 | 0 | // leading zeros, -intDigits + 1 |
169 | 0 | length += 1 - intDigits; |
170 | 0 | } |
171 | 0 | } |
172 | 0 | else { |
173 | 0 | // trailing zeros, total length given by intDigits |
174 | 0 | length = intDigits; |
175 | 0 | } |
176 | 0 | if (aValue < 0) |
177 | 0 | ++length; |
178 | 0 | // grow the string |
179 | 0 | uint32_t oldlength = aDest.Length(); |
180 | 0 | if (!aDest.SetLength(oldlength + length, mozilla::fallible)) |
181 | 0 | return; // out of memory |
182 | 0 | auto dest = aDest.BeginWriting(); |
183 | 0 | std::advance(dest, oldlength); |
184 | 0 | if (aValue < 0) { |
185 | 0 | *dest = '-'; ++dest; |
186 | 0 | } |
187 | 0 | int i; |
188 | 0 | // leading zeros |
189 | 0 | if (intDigits < 1) { |
190 | 0 | *dest = '0'; ++dest; |
191 | 0 | *dest = '.'; ++dest; |
192 | 0 | for (i = 0; i > intDigits; --i) { |
193 | 0 | *dest = '0'; ++dest; |
194 | 0 | } |
195 | 0 | } |
196 | 0 | // mantissa |
197 | 0 | int firstlen = std::min<size_t>(intDigits, endp - buf); |
198 | 0 | for (i = 0; i < firstlen; i++) { |
199 | 0 | *dest = buf[i]; ++dest; |
200 | 0 | } |
201 | 0 | if (i < endp - buf) { |
202 | 0 | if (i > 0) { |
203 | 0 | *dest = '.'; ++dest; |
204 | 0 | } |
205 | 0 | for (; i < endp - buf; i++) { |
206 | 0 | *dest = buf[i]; ++dest; |
207 | 0 | } |
208 | 0 | } |
209 | 0 | // trailing zeros |
210 | 0 | for (; i < intDigits; i++) { |
211 | 0 | *dest = '0'; ++dest; |
212 | 0 | } |
213 | 0 | } |