From 42af1eb0e15823bd77e8203dc15f5d29ed78ec71 Mon Sep 17 00:00:00 2001 From: JoelKatz Date: Tue, 26 Mar 2013 16:41:05 -0700 Subject: [PATCH] New floating point parser. This fixes mishandling "4.3e1". Caret notation is no longer supported. --- src/cpp/ripple/Amount.cpp | 147 +++++++++++--------------------------- 1 file changed, 43 insertions(+), 104 deletions(-) diff --git a/src/cpp/ripple/Amount.cpp b/src/cpp/ripple/Amount.cpp index 2232fae78..7a8af33f2 100644 --- a/src/cpp/ripple/Amount.cpp +++ b/src/cpp/ripple/Amount.cpp @@ -4,6 +4,7 @@ #include #include +#include #include #include #include @@ -257,134 +258,70 @@ std::string STAmount::createHumanCurrency(const uint160& uCurrency) return sCurrency; } -// Assumes trusted input. bool STAmount::setValue(const std::string& sAmount) { // Note: mIsNative and mCurrency must be set already! - uint64 uValue; - int iOffset; - size_t uDecimal = sAmount.find_first_of(mIsNative ? "^" : "."); - size_t uExp = uDecimal == std::string::npos ? sAmount.find_first_of("e") : std::string::npos; - bool bInteger = uDecimal == std::string::npos && uExp == std::string::npos; - mIsNegative = false; - if (bInteger) + static boost::regex reNumber("\\`([+-]?)(\\d*)(\\.(\\d+))?([eE]([+-]?)(\\d+))?\\'"); + boost::smatch smMatch; + + if (!boost::regex_match(sAmount, smMatch, reNumber)) { - // Integer input: does not necessarily mean native. - - try - { - int64 a = sAmount.empty() ? 0 : lexical_cast_st(sAmount); - if (a >= 0) - { - uValue = static_cast(a); - } - else - { - uValue = static_cast(-a); - mIsNegative = true; - } - - } - catch (...) - { - cLog(lsINFO) << "Bad integer amount: " << sAmount; - - return false; - } - iOffset = 0; + cLog(lsWARNING) << "Number not valid: \"" << sAmount << "\""; + return false; } - else if (uExp != std::string::npos) + + // Match fields: 0 = whole input, 1 = sign, 2 = integer portion, 3 = whole fraction (with '.') + // 4 = fraction (without '.'), 5 = whole exponent (with 'e'), 6 = exponent sign, 7 = exponent number + + try { - // e input + mIsNegative = (smMatch[1].matched && (smMatch[1] == "-")); - try + if (!smMatch[3].matched) // integer only { - int64 iInteger = uExp ? lexical_cast_st(sAmount.substr(0, uExp)) : 0; - if (iInteger >= 0) - { - uValue = static_cast(iInteger); - } - else - { - uValue = static_cast(-iInteger); - mIsNegative = true; - } - - iOffset = lexical_cast_st(sAmount.substr(uExp+1)); + mValue = lexical_cast_s(smMatch[2]); + mOffset = 0; + } + else + { // integer and fraction + mValue = lexical_cast_s(smMatch[2] + smMatch[4]); + mOffset = -(smMatch[4].length()); } - catch (...) - { - cLog(lsINFO) << "Bad e amount: " << sAmount; - return false; + if (smMatch[5].matched) + { // we have an exponent + if (smMatch[6].matched && (smMatch[6] == "-")) + mOffset -= lexical_cast_s(smMatch[7]); + else + mOffset += lexical_cast_s(smMatch[7]); } } - else + catch (...) { - // Float input: has a decimal - - // Example size decimal size-decimal offset - // ^1 2 0 2 -1 - // 123^ 4 3 1 0 - // 1^23 4 1 3 -2 - try - { - iOffset = -int(sAmount.size() - uDecimal - 1); - - // Issolate integer and fraction. - uint64 uInteger; - int64 iInteger = uDecimal ? lexical_cast_st(sAmount.substr(0, uDecimal)) : 0; - if (iInteger >= 0) - { - uInteger = static_cast(iInteger); - } - else - { - uInteger = static_cast(-iInteger); - mIsNegative = true; - } - - uint64 uFraction = iOffset ? lexical_cast_st(sAmount.substr(uDecimal+1)) : 0; - - // Scale the integer portion to the same offset as the fraction. - uValue = uInteger; - for (int i = -iOffset; i--;) - uValue *= 10; - - // Add in the fraction. - uValue += uFraction; - } - catch (...) - { - cLog(lsINFO) << "Bad float amount: " << sAmount; - - return false; - } + cLog(lsWARNING) << "Number not parsed: \"" << sAmount << "\""; + return false; } + cLog(lsTRACE) << "Float \"" << sAmount << "\" parsed to " << mValue << " : " << mOffset; + if (mIsNative) { - if (bInteger) - iOffset = -SYSTEM_CURRENCY_PRECISION; + if (smMatch[2].matched) + mOffset -= SYSTEM_CURRENCY_PRECISION; - while (iOffset > -SYSTEM_CURRENCY_PRECISION) { - uValue *= 10; - --iOffset; + while (mOffset > -SYSTEM_CURRENCY_PRECISION) { + mValue *= 10; + --mOffset; } - while (iOffset < -SYSTEM_CURRENCY_PRECISION) { - uValue /= 10; - ++iOffset; + while (mOffset < -SYSTEM_CURRENCY_PRECISION) { + mValue /= 10; + ++mOffset; } - - mValue = uValue; } else - { - mValue = uValue; - mOffset = iOffset; canonicalize(); - } + return true; } @@ -1287,11 +1224,13 @@ BOOST_AUTO_TEST_CASE( setValue_test ) { STAmount saTmp; +#if 0 // Check native floats saTmp.setFullValue("1^0"); BOOST_CHECK_MESSAGE(SYSTEM_CURRENCY_PARTS == saTmp.getNValue(), "float integer failed"); saTmp.setFullValue("0^1"); BOOST_CHECK_MESSAGE(SYSTEM_CURRENCY_PARTS/10 == saTmp.getNValue(), "float fraction failed"); saTmp.setFullValue("0^12"); BOOST_CHECK_MESSAGE(12*SYSTEM_CURRENCY_PARTS/100 == saTmp.getNValue(), "float fraction failed"); saTmp.setFullValue("1^2"); BOOST_CHECK_MESSAGE(SYSTEM_CURRENCY_PARTS+(2*SYSTEM_CURRENCY_PARTS/10) == saTmp.getNValue(), "float combined failed"); +#endif // Check native integer saTmp.setFullValue("1"); BOOST_CHECK_MESSAGE(1 == saTmp.getNValue(), "integer failed");