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.cpp215
1 files changed, 215 insertions, 0 deletions
diff --git a/dom/xslt/base/txDouble.cpp b/dom/xslt/base/txDouble.cpp
new file mode 100644
index 000000000..f52d1b885
--- /dev/null
+++ b/dom/xslt/base/txDouble.cpp
@@ -0,0 +1,215 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/* 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:
+ typedef char16_t input_type;
+ typedef char16_t value_type;
+ txStringToDouble(): mState(eWhitestart), mSign(ePositive) {}
+
+ void
+ write(const input_type* aSource, uint32_t aSourceLength)
+ {
+ if (mState == eIllegal) {
+ return;
+ }
+ uint32_t i = 0;
+ char16_t c;
+ for ( ; i < aSourceLength; ++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 mSign*PR_strtod(mBuffer.get(), 0);
+ }
+private:
+ nsAutoCString mBuffer;
+ enum {
+ eWhitestart,
+ eDecimal,
+ eMantissa,
+ eWhiteend,
+ eIllegal
+ } mState;
+ enum {
+ eNegative = -1,
+ ePositive = 1
+ } mSign;
+};
+
+double txDouble::toDouble(const nsAString& aSrc)
+{
+ txStringToDouble sink;
+ nsAString::const_iterator fromBegin, fromEnd;
+ copy_string(aSrc.BeginReading(fromBegin), aSrc.EndReading(fromEnd), sink);
+ 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 (mozilla::IsNaN(aValue)) {
+ aDest.AppendLiteral("NaN");
+ return;
+ }
+ if (mozilla::IsInfinite(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
+ nsAString::iterator dest;
+ aDest.BeginWriting(dest).advance(int32_t(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;
+ }
+}