summaryrefslogtreecommitdiff
path: root/src/mongo/base
diff options
context:
space:
mode:
authorAndy Schwerin <schwerin@10gen.com>2013-03-04 10:08:41 -0500
committerAndy Schwerin <schwerin@10gen.com>2013-03-11 13:40:23 -0400
commit3e77e29635c719fecec008c15542fee68d50a4ce (patch)
tree398dfb992bd55859c90a0b91e719a99239e419aa /src/mongo/base
parentd36db8ac30a56d39f4af58e573ee417450798c96 (diff)
downloadmongo-3e77e29635c719fecec008c15542fee68d50a4ce.tar.gz
Implement parseNumberFromStringWithBase<double>().
Diffstat (limited to 'src/mongo/base')
-rw-r--r--src/mongo/base/parse_number.cpp31
-rw-r--r--src/mongo/base/parse_number_test.cpp64
2 files changed, 95 insertions, 0 deletions
diff --git a/src/mongo/base/parse_number.cpp b/src/mongo/base/parse_number.cpp
index 775727d7337..3c84845a788 100644
--- a/src/mongo/base/parse_number.cpp
+++ b/src/mongo/base/parse_number.cpp
@@ -15,6 +15,8 @@
#include "mongo/base/parse_number.h"
+#include <cerrno>
+#include <cstdlib>
#include <limits>
#include "mongo/platform/cstdint.h"
@@ -181,5 +183,34 @@ namespace mongo {
DEFINE_PARSE_NUMBER_FROM_STRING_WITH_BASE(unsigned int)
DEFINE_PARSE_NUMBER_FROM_STRING_WITH_BASE(int8_t);
DEFINE_PARSE_NUMBER_FROM_STRING_WITH_BASE(uint8_t);
+#undef DEFINE_PARSE_NUMBER_FROM_STRING_WITH_BASE
+
+ template <>
+ Status parseNumberFromStringWithBase<double>(const StringData& stringValue,
+ int base,
+ double* result) {
+ if (base != 0) {
+ return Status(ErrorCodes::BadValue,
+ "Must pass 0 as base to parseNumberFromStringWithBase<double>.");
+ }
+ if (stringValue.empty())
+ return Status(ErrorCodes::FailedToParse, "Empty string");
+
+ if (isspace(stringValue[0]))
+ return Status(ErrorCodes::FailedToParse, "Leading whitespace");
+
+ std::string str = stringValue.toString();
+ const char* cStr = str.c_str();
+ char* endp;
+ errno = 0;
+ double d = strtod(cStr, &endp);
+ int actualErrno = errno;
+ if (endp != stringValue.size() + cStr)
+ return Status(ErrorCodes::FailedToParse, "Did not consume whole number.");
+ if (actualErrno == ERANGE)
+ return Status(ErrorCodes::FailedToParse, "Out of range");
+ *result = d;
+ return Status::OK();
+ }
} // namespace mongo
diff --git a/src/mongo/base/parse_number_test.cpp b/src/mongo/base/parse_number_test.cpp
index e18066b742d..3a775f1878a 100644
--- a/src/mongo/base/parse_number_test.cpp
+++ b/src/mongo/base/parse_number_test.cpp
@@ -222,5 +222,69 @@ namespace {
ASSERT_PARSES(uint8_t, std::string(mongoutils::str::stream() << i), i);
}
+ TEST(Double, TestRejectingBadBases) {
+ double ignored;
+
+ // Only supported base for parseNumberFromStringWithBase<double> is 0.
+ ASSERT_EQUALS(ErrorCodes::BadValue, parseNumberFromStringWithBase("0", -1, &ignored));
+ ASSERT_EQUALS(ErrorCodes::BadValue, parseNumberFromStringWithBase("0", 1, &ignored));
+ ASSERT_EQUALS(ErrorCodes::BadValue, parseNumberFromStringWithBase("0", 8, &ignored));
+ ASSERT_EQUALS(ErrorCodes::BadValue, parseNumberFromStringWithBase("0", 10, &ignored));
+ ASSERT_EQUALS(ErrorCodes::BadValue, parseNumberFromStringWithBase("0", 16, &ignored));
+ }
+
+ TEST(Double, TestParsingGarbage) {
+ double d;
+ CommonNumberParsingTests<double>::TestParsingGarbage();
+ ASSERT_EQUALS(ErrorCodes::FailedToParse, parseNumberFromString<double>("1.0.1", &d));
+ ASSERT_EQUALS(ErrorCodes::FailedToParse, parseNumberFromString<double>("1.0-1", &d));
+ ASSERT_EQUALS(ErrorCodes::FailedToParse, parseNumberFromString<double>(" 1.0", &d));
+ ASSERT_EQUALS(ErrorCodes::FailedToParse, parseNumberFromString<double>("1.0P4", &d));
+ ASSERT_EQUALS(ErrorCodes::FailedToParse, parseNumberFromString<double>("1e6 ", &d));
+ ASSERT_EQUALS(ErrorCodes::FailedToParse, parseNumberFromString<double>(" 1e6", &d));
+ ASSERT_EQUALS(ErrorCodes::FailedToParse, parseNumberFromString<double>("1e6 ", &d));
+ ASSERT_EQUALS(ErrorCodes::FailedToParse, parseNumberFromString<double>(" 1e6", &d));
+ ASSERT_EQUALS(ErrorCodes::FailedToParse, parseNumberFromString<double>("0xabcab.defPa", &d));
+ }
+
+ TEST(Double, TestParsingOverflow) {
+ double d;
+ ASSERT_EQUALS(ErrorCodes::FailedToParse, parseNumberFromString("1e309", &d));
+ ASSERT_EQUALS(ErrorCodes::FailedToParse, parseNumberFromString("-1e309", &d));
+ ASSERT_EQUALS(ErrorCodes::FailedToParse, parseNumberFromString("1e-309", &d));
+ ASSERT_EQUALS(ErrorCodes::FailedToParse, parseNumberFromString("-1e-309", &d));
+ }
+
+ TEST(Double, TestParsingNan) {
+ double d = 0;
+ ASSERT_OK(parseNumberFromString("NaN", &d));
+ ASSERT_TRUE(isnan(d));
+ }
+
+ TEST(Double, TestParsingInfinity) {
+ double d = 0;
+ ASSERT_OK(parseNumberFromString("infinity", &d));
+ ASSERT_TRUE(isinf(d));
+ d = 0;
+ ASSERT_OK(parseNumberFromString("-Infinity", &d));
+ ASSERT_TRUE(isinf(d));
+ }
+
+ TEST(Double, TestParsingNormal) {
+ ASSERT_PARSES(double, "10", 10);
+ ASSERT_PARSES(double, "0", 0);
+ ASSERT_PARSES(double, "1", 1);
+ ASSERT_PARSES(double, "0xff", 0xff);
+ ASSERT_PARSES(double, "-10", -10);
+ ASSERT_PARSES(double, "-0xff", -0xff);
+
+ ASSERT_PARSES(double, "1e8", 1e8);
+ ASSERT_PARSES(double, "1e-8", 1e-8);
+ ASSERT_PARSES(double, "12e-8", 12e-8);
+ ASSERT_PARSES(double, "-485.381e-8", -485.381e-8);
+
+ ASSERT_PARSES(double, "0xabcab.defdefP-10", 0xabcab.defdefP-10);
+ }
+
} // namespace
} // namespace mongo