summaryrefslogtreecommitdiffstats
path: root/dom/xslt/base/txDouble.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'dom/xslt/base/txDouble.cpp')
-rw-r--r--dom/xslt/base/txDouble.cpp194
1 files changed, 194 insertions, 0 deletions
diff --git a/dom/xslt/base/txDouble.cpp b/dom/xslt/base/txDouble.cpp
new file mode 100644
index 0000000000..ad7fa690be
--- /dev/null
+++ b/dom/xslt/base/txDouble.cpp
@@ -0,0 +1,194 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#include "mozilla/FloatingPoint.h"
+
+#include "nsString.h"
+#include "txCore.h"
+#include "txXMLUtils.h"
+#include <math.h>
+#include <stdlib.h>
+#include <algorithm>
+#ifdef WIN32
+# include <float.h>
+#endif
+#include "prdtoa.h"
+
+/*
+ * Utility class for doubles
+ */
+
+/*
+ * Converts the given String to a double, if the String value does not
+ * represent a double, NaN will be returned
+ */
+class txStringToDouble {
+ public:
+ txStringToDouble() : mState(eWhitestart), mSign(ePositive) {}
+
+ void Parse(const nsAString& aSource) {
+ if (mState == eIllegal) {
+ return;
+ }
+ uint32_t i = 0;
+ char16_t c;
+ auto len = aSource.Length();
+ for (; i < len; ++i) {
+ c = aSource[i];
+ switch (mState) {
+ case eWhitestart:
+ if (c == '-') {
+ mState = eDecimal;
+ mSign = eNegative;
+ } else if (c >= '0' && c <= '9') {
+ mState = eDecimal;
+ mBuffer.Append((char)c);
+ } else if (c == '.') {
+ mState = eMantissa;
+ mBuffer.Append((char)c);
+ } else if (!XMLUtils::isWhitespace(c)) {
+ mState = eIllegal;
+ return;
+ }
+ break;
+ case eDecimal:
+ if (c >= '0' && c <= '9') {
+ mBuffer.Append((char)c);
+ } else if (c == '.') {
+ mState = eMantissa;
+ mBuffer.Append((char)c);
+ } else if (XMLUtils::isWhitespace(c)) {
+ mState = eWhiteend;
+ } else {
+ mState = eIllegal;
+ return;
+ }
+ break;
+ case eMantissa:
+ if (c >= '0' && c <= '9') {
+ mBuffer.Append((char)c);
+ } else if (XMLUtils::isWhitespace(c)) {
+ mState = eWhiteend;
+ } else {
+ mState = eIllegal;
+ return;
+ }
+ break;
+ case eWhiteend:
+ if (!XMLUtils::isWhitespace(c)) {
+ mState = eIllegal;
+ return;
+ }
+ break;
+ default:
+ break;
+ }
+ }
+ }
+
+ double getDouble() {
+ if (mState == eIllegal || mBuffer.IsEmpty() ||
+ (mBuffer.Length() == 1 && mBuffer[0] == '.')) {
+ return mozilla::UnspecifiedNaN<double>();
+ }
+ return static_cast<double>(mSign) * PR_strtod(mBuffer.get(), nullptr);
+ }
+
+ private:
+ nsAutoCString mBuffer;
+ enum { eWhitestart, eDecimal, eMantissa, eWhiteend, eIllegal } mState;
+ enum { eNegative = -1, ePositive = 1 } mSign;
+};
+
+double txDouble::toDouble(const nsAString& aSrc) {
+ txStringToDouble sink;
+ sink.Parse(aSrc);
+ return sink.getDouble();
+}
+
+/*
+ * Converts the value of the given double to a String, and places
+ * The result into the destination String.
+ * @return the given dest string
+ */
+void txDouble::toString(double aValue, nsAString& aDest) {
+ // check for special cases
+
+ if (std::isnan(aValue)) {
+ aDest.AppendLiteral("NaN");
+ return;
+ }
+ if (std::isinf(aValue)) {
+ if (aValue < 0) aDest.Append(char16_t('-'));
+ aDest.AppendLiteral("Infinity");
+ return;
+ }
+
+ // Mantissa length is 17, so this is plenty
+ const int buflen = 20;
+ char buf[buflen];
+
+ int intDigits, sign;
+ char* endp;
+ PR_dtoa(aValue, 0, 0, &intDigits, &sign, &endp, buf, buflen - 1);
+
+ // compute length
+ int32_t length = endp - buf;
+ if (length > intDigits) {
+ // decimal point needed
+ ++length;
+ if (intDigits < 1) {
+ // leading zeros, -intDigits + 1
+ length += 1 - intDigits;
+ }
+ } else {
+ // trailing zeros, total length given by intDigits
+ length = intDigits;
+ }
+ if (aValue < 0) ++length;
+ // grow the string
+ uint32_t oldlength = aDest.Length();
+ if (!aDest.SetLength(oldlength + length, mozilla::fallible))
+ return; // out of memory
+ auto dest = aDest.BeginWriting();
+ std::advance(dest, oldlength);
+ if (aValue < 0) {
+ *dest = '-';
+ ++dest;
+ }
+ int i;
+ // leading zeros
+ if (intDigits < 1) {
+ *dest = '0';
+ ++dest;
+ *dest = '.';
+ ++dest;
+ for (i = 0; i > intDigits; --i) {
+ *dest = '0';
+ ++dest;
+ }
+ }
+ // mantissa
+ int firstlen = std::min<size_t>(intDigits, endp - buf);
+ for (i = 0; i < firstlen; i++) {
+ *dest = buf[i];
+ ++dest;
+ }
+ if (i < endp - buf) {
+ if (i > 0) {
+ *dest = '.';
+ ++dest;
+ }
+ for (; i < endp - buf; i++) {
+ *dest = buf[i];
+ ++dest;
+ }
+ }
+ // trailing zeros
+ for (; i < intDigits; i++) {
+ *dest = '0';
+ ++dest;
+ }
+}