no bug - Import translations from android-l10n r=release a=l10n CLOSED TREE
[gecko.git] / dom / xslt / base / txDouble.cpp
blobad7fa690be8c84ee815c77d751215c82035dfac4
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
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/. */
6 #include "mozilla/FloatingPoint.h"
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"
20 * Utility class for doubles
24 * Converts the given String to a double, if the String value does not
25 * represent a double, NaN will be returned
27 class txStringToDouble {
28 public:
29 txStringToDouble() : mState(eWhitestart), mSign(ePositive) {}
31 void Parse(const nsAString& aSource) {
32 if (mState == eIllegal) {
33 return;
35 uint32_t i = 0;
36 char16_t c;
37 auto len = aSource.Length();
38 for (; i < len; ++i) {
39 c = aSource[i];
40 switch (mState) {
41 case eWhitestart:
42 if (c == '-') {
43 mState = eDecimal;
44 mSign = eNegative;
45 } else if (c >= '0' && c <= '9') {
46 mState = eDecimal;
47 mBuffer.Append((char)c);
48 } else if (c == '.') {
49 mState = eMantissa;
50 mBuffer.Append((char)c);
51 } else if (!XMLUtils::isWhitespace(c)) {
52 mState = eIllegal;
53 return;
55 break;
56 case eDecimal:
57 if (c >= '0' && c <= '9') {
58 mBuffer.Append((char)c);
59 } else if (c == '.') {
60 mState = eMantissa;
61 mBuffer.Append((char)c);
62 } else if (XMLUtils::isWhitespace(c)) {
63 mState = eWhiteend;
64 } else {
65 mState = eIllegal;
66 return;
68 break;
69 case eMantissa:
70 if (c >= '0' && c <= '9') {
71 mBuffer.Append((char)c);
72 } else if (XMLUtils::isWhitespace(c)) {
73 mState = eWhiteend;
74 } else {
75 mState = eIllegal;
76 return;
78 break;
79 case eWhiteend:
80 if (!XMLUtils::isWhitespace(c)) {
81 mState = eIllegal;
82 return;
84 break;
85 default:
86 break;
91 double getDouble() {
92 if (mState == eIllegal || mBuffer.IsEmpty() ||
93 (mBuffer.Length() == 1 && mBuffer[0] == '.')) {
94 return mozilla::UnspecifiedNaN<double>();
96 return static_cast<double>(mSign) * PR_strtod(mBuffer.get(), nullptr);
99 private:
100 nsAutoCString mBuffer;
101 enum { eWhitestart, eDecimal, eMantissa, eWhiteend, eIllegal } mState;
102 enum { eNegative = -1, ePositive = 1 } mSign;
105 double txDouble::toDouble(const nsAString& aSrc) {
106 txStringToDouble sink;
107 sink.Parse(aSrc);
108 return sink.getDouble();
112 * Converts the value of the given double to a String, and places
113 * The result into the destination String.
114 * @return the given dest string
116 void txDouble::toString(double aValue, nsAString& aDest) {
117 // check for special cases
119 if (std::isnan(aValue)) {
120 aDest.AppendLiteral("NaN");
121 return;
123 if (std::isinf(aValue)) {
124 if (aValue < 0) aDest.Append(char16_t('-'));
125 aDest.AppendLiteral("Infinity");
126 return;
129 // Mantissa length is 17, so this is plenty
130 const int buflen = 20;
131 char buf[buflen];
133 int intDigits, sign;
134 char* endp;
135 PR_dtoa(aValue, 0, 0, &intDigits, &sign, &endp, buf, buflen - 1);
137 // compute length
138 int32_t length = endp - buf;
139 if (length > intDigits) {
140 // decimal point needed
141 ++length;
142 if (intDigits < 1) {
143 // leading zeros, -intDigits + 1
144 length += 1 - intDigits;
146 } else {
147 // trailing zeros, total length given by intDigits
148 length = intDigits;
150 if (aValue < 0) ++length;
151 // grow the string
152 uint32_t oldlength = aDest.Length();
153 if (!aDest.SetLength(oldlength + length, mozilla::fallible))
154 return; // out of memory
155 auto dest = aDest.BeginWriting();
156 std::advance(dest, oldlength);
157 if (aValue < 0) {
158 *dest = '-';
159 ++dest;
161 int i;
162 // leading zeros
163 if (intDigits < 1) {
164 *dest = '0';
165 ++dest;
166 *dest = '.';
167 ++dest;
168 for (i = 0; i > intDigits; --i) {
169 *dest = '0';
170 ++dest;
173 // mantissa
174 int firstlen = std::min<size_t>(intDigits, endp - buf);
175 for (i = 0; i < firstlen; i++) {
176 *dest = buf[i];
177 ++dest;
179 if (i < endp - buf) {
180 if (i > 0) {
181 *dest = '.';
182 ++dest;
184 for (; i < endp - buf; i++) {
185 *dest = buf[i];
186 ++dest;
189 // trailing zeros
190 for (; i < intDigits; i++) {
191 *dest = '0';
192 ++dest;