dom/xslt/base/txDouble.cpp

changeset 0
6474c204b198
     1.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     1.2 +++ b/dom/xslt/base/txDouble.cpp	Wed Dec 31 06:09:35 2014 +0100
     1.3 @@ -0,0 +1,215 @@
     1.4 +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
     1.5 +/* This Source Code Form is subject to the terms of the Mozilla Public
     1.6 + * License, v. 2.0. If a copy of the MPL was not distributed with this
     1.7 + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
     1.8 +
     1.9 +#include "mozilla/FloatingPoint.h"
    1.10 +
    1.11 +#include "nsString.h"
    1.12 +#include "txCore.h"
    1.13 +#include "txXMLUtils.h"
    1.14 +#include <math.h>
    1.15 +#include <stdlib.h>
    1.16 +#include <algorithm>
    1.17 +#ifdef WIN32
    1.18 +#include <float.h>
    1.19 +#endif
    1.20 +#include "prdtoa.h"
    1.21 +
    1.22 +/*
    1.23 + * Utility class for doubles
    1.24 + */
    1.25 +
    1.26 +/*
    1.27 + * Converts the given String to a double, if the String value does not
    1.28 + * represent a double, NaN will be returned
    1.29 + */
    1.30 +class txStringToDouble
    1.31 +{
    1.32 +public:
    1.33 +    typedef char16_t input_type;
    1.34 +    typedef char16_t value_type;
    1.35 +    txStringToDouble(): mState(eWhitestart), mSign(ePositive) {}
    1.36 +
    1.37 +    void
    1.38 +    write(const input_type* aSource, uint32_t aSourceLength)
    1.39 +    {
    1.40 +        if (mState == eIllegal) {
    1.41 +            return;
    1.42 +        }
    1.43 +        uint32_t i = 0;
    1.44 +        char16_t c;
    1.45 +        for ( ; i < aSourceLength; ++i) {
    1.46 +            c = aSource[i];
    1.47 +            switch (mState) {
    1.48 +                case eWhitestart:
    1.49 +                    if (c == '-') {
    1.50 +                        mState = eDecimal;
    1.51 +                        mSign = eNegative;
    1.52 +                    }
    1.53 +                    else if (c >= '0' && c <= '9') {
    1.54 +                        mState = eDecimal;
    1.55 +                        mBuffer.Append((char)c);
    1.56 +                    }
    1.57 +                    else if (c == '.') {
    1.58 +                        mState = eMantissa;
    1.59 +                        mBuffer.Append((char)c);
    1.60 +                    }
    1.61 +                    else if (!XMLUtils::isWhitespace(c)) {
    1.62 +                        mState = eIllegal;
    1.63 +                        return;
    1.64 +                    }
    1.65 +                    break;
    1.66 +                case eDecimal:
    1.67 +                    if (c >= '0' && c <= '9') {
    1.68 +                        mBuffer.Append((char)c);
    1.69 +                    }
    1.70 +                    else if (c == '.') {
    1.71 +                        mState = eMantissa;
    1.72 +                        mBuffer.Append((char)c);
    1.73 +                    }
    1.74 +                    else if (XMLUtils::isWhitespace(c)) {
    1.75 +                        mState = eWhiteend;
    1.76 +                    }
    1.77 +                    else {
    1.78 +                        mState = eIllegal;
    1.79 +                        return;
    1.80 +                    }
    1.81 +                    break;
    1.82 +                case eMantissa:
    1.83 +                    if (c >= '0' && c <= '9') {
    1.84 +                        mBuffer.Append((char)c);
    1.85 +                    }
    1.86 +                    else if (XMLUtils::isWhitespace(c)) {
    1.87 +                        mState = eWhiteend;
    1.88 +                    }
    1.89 +                    else {
    1.90 +                        mState = eIllegal;
    1.91 +                        return;
    1.92 +                    }
    1.93 +                    break;
    1.94 +                case eWhiteend:
    1.95 +                    if (!XMLUtils::isWhitespace(c)) {
    1.96 +                        mState = eIllegal;
    1.97 +                        return;
    1.98 +                    }
    1.99 +                    break;
   1.100 +                default:
   1.101 +                    break;
   1.102 +            }
   1.103 +        }
   1.104 +    }
   1.105 +
   1.106 +    double
   1.107 +    getDouble()
   1.108 +    {
   1.109 +        if (mState == eIllegal || mBuffer.IsEmpty() ||
   1.110 +            (mBuffer.Length() == 1 && mBuffer[0] == '.')) {
   1.111 +            return mozilla::UnspecifiedNaN<double>();
   1.112 +        }
   1.113 +        return mSign*PR_strtod(mBuffer.get(), 0);
   1.114 +    }
   1.115 +private:
   1.116 +    nsAutoCString mBuffer;
   1.117 +    enum {
   1.118 +        eWhitestart,
   1.119 +        eDecimal,
   1.120 +        eMantissa,
   1.121 +        eWhiteend,
   1.122 +        eIllegal
   1.123 +    } mState;
   1.124 +    enum {
   1.125 +        eNegative = -1,
   1.126 +        ePositive = 1
   1.127 +    } mSign;
   1.128 +};
   1.129 +
   1.130 +double txDouble::toDouble(const nsAString& aSrc)
   1.131 +{
   1.132 +    txStringToDouble sink;
   1.133 +    nsAString::const_iterator fromBegin, fromEnd;
   1.134 +    copy_string(aSrc.BeginReading(fromBegin), aSrc.EndReading(fromEnd), sink);
   1.135 +    return sink.getDouble();
   1.136 +}
   1.137 +
   1.138 +/*
   1.139 + * Converts the value of the given double to a String, and places
   1.140 + * The result into the destination String.
   1.141 + * @return the given dest string
   1.142 + */
   1.143 +void txDouble::toString(double aValue, nsAString& aDest)
   1.144 +{
   1.145 +
   1.146 +    // check for special cases
   1.147 +
   1.148 +    if (mozilla::IsNaN(aValue)) {
   1.149 +        aDest.AppendLiteral("NaN");
   1.150 +        return;
   1.151 +    }
   1.152 +    if (mozilla::IsInfinite(aValue)) {
   1.153 +        if (aValue < 0)
   1.154 +            aDest.Append(char16_t('-'));
   1.155 +        aDest.AppendLiteral("Infinity");
   1.156 +        return;
   1.157 +    }
   1.158 +
   1.159 +    // Mantissa length is 17, so this is plenty
   1.160 +    const int buflen = 20;
   1.161 +    char buf[buflen];
   1.162 +
   1.163 +    int intDigits, sign;
   1.164 +    char* endp;
   1.165 +    PR_dtoa(aValue, 0, 0, &intDigits, &sign, &endp, buf, buflen - 1);
   1.166 +
   1.167 +    // compute length
   1.168 +    int32_t length = endp - buf;
   1.169 +    if (length > intDigits) {
   1.170 +        // decimal point needed
   1.171 +        ++length;
   1.172 +        if (intDigits < 1) {
   1.173 +            // leading zeros, -intDigits + 1
   1.174 +            length += 1 - intDigits;
   1.175 +        }
   1.176 +    }
   1.177 +    else {
   1.178 +        // trailing zeros, total length given by intDigits
   1.179 +        length = intDigits;
   1.180 +    }
   1.181 +    if (aValue < 0)
   1.182 +        ++length;
   1.183 +    // grow the string
   1.184 +    uint32_t oldlength = aDest.Length();
   1.185 +    if (!aDest.SetLength(oldlength + length, mozilla::fallible_t()))
   1.186 +        return; // out of memory
   1.187 +    nsAString::iterator dest;
   1.188 +    aDest.BeginWriting(dest).advance(int32_t(oldlength));
   1.189 +    if (aValue < 0) {
   1.190 +        *dest = '-'; ++dest;
   1.191 +    }
   1.192 +    int i;
   1.193 +    // leading zeros
   1.194 +    if (intDigits < 1) {
   1.195 +        *dest = '0'; ++dest;
   1.196 +        *dest = '.'; ++dest;
   1.197 +        for (i = 0; i > intDigits; --i) {
   1.198 +            *dest = '0'; ++dest;
   1.199 +        }
   1.200 +    }
   1.201 +    // mantissa
   1.202 +    int firstlen = std::min<size_t>(intDigits, endp - buf);
   1.203 +    for (i = 0; i < firstlen; i++) {
   1.204 +        *dest = buf[i]; ++dest;
   1.205 +    }
   1.206 +    if (i < endp - buf) {
   1.207 +        if (i > 0) {
   1.208 +            *dest = '.'; ++dest;
   1.209 +        }
   1.210 +        for (; i < endp - buf; i++) {
   1.211 +            *dest = buf[i]; ++dest;
   1.212 +        }
   1.213 +    }
   1.214 +    // trailing zeros
   1.215 +    for (; i < intDigits; i++) {
   1.216 +        *dest = '0'; ++dest;
   1.217 +    }
   1.218 +}

mercurial