summaryrefslogtreecommitdiffstats
path: root/vespalib
diff options
context:
space:
mode:
authorArne Juul <arnej@yahoo-inc.com>2019-06-12 12:03:25 +0000
committerArne Juul <arnej@yahoo-inc.com>2019-06-12 12:09:47 +0000
commit64fb9d91dcfd8511c94ecae3ca0a7652010e3892 (patch)
tree686536d56996fe196babc7fdae107e0cf6e079e1 /vespalib
parent07d3c4efed886275aa86b5c8587b768904237e04 (diff)
* no exception on underflow in strtof() and strtod()
* still throw exception on overflow instead of returning HUGE_VAL * change exception message to make it readable * unit test float and double conversion from denormalized numbers
Diffstat (limited to 'vespalib')
-rw-r--r--vespalib/src/tests/stllike/asciistream_test.cpp65
-rw-r--r--vespalib/src/vespa/vespalib/stllike/asciistream.cpp25
2 files changed, 83 insertions, 7 deletions
diff --git a/vespalib/src/tests/stllike/asciistream_test.cpp b/vespalib/src/tests/stllike/asciistream_test.cpp
index b0f6d8cb455..e38a7e8b3e5 100644
--- a/vespalib/src/tests/stllike/asciistream_test.cpp
+++ b/vespalib/src/tests/stllike/asciistream_test.cpp
@@ -4,7 +4,9 @@
#include <vespa/vespalib/testkit/testapp.h>
#include <vespa/vespalib/stllike/asciistream.h>
#include <vespa/vespalib/util/exceptions.h>
+#include <vespa/vespalib/locale/c.h>
#include <iomanip>
+#include <float.h>
using namespace vespalib;
@@ -26,6 +28,7 @@ public:
void testMoveIsWellDefined();
void testIllegalNumbers();
void testDouble();
+ void testFloat();
void testStateSaver();
};
@@ -83,10 +86,10 @@ AsciistreamTest::testIllegalNumbers()
is << "777777777777";
EXPECT_EQUAL(24u, is.size());
uint64_t l(0);
- EXPECT_EXCEPTION(is >> l, IllegalArgumentException, "value is outside of range '777777777777777777777777'");
+ EXPECT_EXCEPTION(is >> l, IllegalArgumentException, "value '777777777777777777777777' is outside of range");
EXPECT_EQUAL(24u, is.size());
int64_t li(0);
- EXPECT_EXCEPTION(is >> li, IllegalArgumentException, "value is outside of range '777777777777777777777777'");
+ EXPECT_EXCEPTION(is >> li, IllegalArgumentException, "value '777777777777777777777777' is outside of range");
EXPECT_EQUAL(24u, is.size());
}
{
@@ -102,13 +105,13 @@ AsciistreamTest::testIllegalNumbers()
asciistream is("7777777777777777777777777777777777777777");
EXPECT_EQUAL(40u, is.size());
float f(0);
- EXPECT_EXCEPTION(is >> f, IllegalArgumentException, "float value is outside of range '7777777777777777777777777777777777777777'");
+ EXPECT_EXCEPTION(is >> f, IllegalArgumentException, "float value '7777777777777777777777777777777777777777' is outside of range");
EXPECT_EQUAL(40u, is.size());
vespalib::string tmp = is.str();
is << "e" << tmp;
EXPECT_EQUAL(81u, is.size());
double d(0);
- EXPECT_EXCEPTION(is >> d, IllegalArgumentException, "double value is outside of range '7777777777777777777777777777777777777777e7777777777777777777777777777777777777777'");
+ EXPECT_EXCEPTION(is >> d, IllegalArgumentException, "double value '7777777777777777777777777777777777777777e7777777777777777777777777777777777777777' is outside of range");
EXPECT_EQUAL(81u, is.size());
}
{
@@ -481,6 +484,59 @@ AsciistreamTest::testDouble() {
VERIFY_DOUBLE_SERIALIZATION(0.0, "0.0", automatic << forcedot, 1);
VERIFY_DOUBLE_SERIALIZATION(0.0, "0.0", automatic << forcedot, 16);
VERIFY_DOUBLE_SERIALIZATION(maxInteger, "9007199254740992.0", automatic << forcedot, 16);
+
+ asciistream as;
+ as.clear();
+ as << (3 * std::numeric_limits<double>::min());
+ double dv = 0;
+ as >> dv;
+ EXPECT_TRUE(dv > 0);
+
+ as.clear();
+ as << (3 * std::numeric_limits<double>::denorm_min());
+ dv = 0;
+ as >> dv;
+ EXPECT_TRUE(dv > 0);
+
+ as.clear();
+ as << "1.0e-325";
+ dv = 42.0;
+ as >> dv;
+ EXPECT_EQUAL(dv, 0.0);
+
+ as.clear();
+ as << "1.0e666";
+ dv = 42.0;
+ EXPECT_EXCEPTION(as >> dv, IllegalArgumentException, "double value '1.0e666' is outside of range.");
+ EXPECT_EQUAL(dv, 42.0);
+}
+
+void
+AsciistreamTest::testFloat() {
+ float f = 0;
+ asciistream as("-5.490412E-39");
+ try {
+ as >> f;
+ } catch (std::exception &e) {
+ EXPECT_EQUAL("should not reach this point", e.what());
+ }
+ EXPECT_EQUAL(f, -5.490412E-39f);
+
+ as.clear();
+ as << "0.0001E-50";
+ f = 42.0;
+ try {
+ as >> f;
+ } catch (std::exception &e) {
+ EXPECT_EQUAL("should not reach this point", e.what());
+ }
+ EXPECT_EQUAL(f, 0.0);
+
+ as.clear();
+ as << "123.4E50";
+ f = 42.0;
+ EXPECT_EXCEPTION(as >> f, IllegalArgumentException, "float value '123.4E50' is outside of range.");
+ EXPECT_EQUAL(f, 42.0);
}
void
@@ -547,6 +603,7 @@ AsciistreamTest::Main()
testGetLine();
testIllegalNumbers();
testDouble();
+ testFloat();
testStateSaver();
TEST_DONE();
}
diff --git a/vespalib/src/vespa/vespalib/stllike/asciistream.cpp b/vespalib/src/vespa/vespalib/stllike/asciistream.cpp
index 30a963c374c..499171dc6e7 100644
--- a/vespalib/src/vespa/vespalib/stllike/asciistream.cpp
+++ b/vespalib/src/vespa/vespalib/stllike/asciistream.cpp
@@ -10,6 +10,7 @@
#include <limits>
#include <stdexcept>
#include <cassert>
+#include <math.h>
#include <vespa/log/log.h>
LOG_SETUP(".vespalib.stllike.asciistream");
@@ -154,7 +155,7 @@ void throwInputError(int e, const char * t, const char * buf)
if (e == 0) {
throw IllegalArgumentException("Failed decoding a " + string(t) + " from '" + string(buf) + "'.", VESPA_STRLOC);
} else if (errno == ERANGE) {
- throw IllegalArgumentException(string(t) + " value is outside of range '" + string(buf) + "'.", VESPA_STRLOC);
+ throw IllegalArgumentException(string(t) + " value '" + string(buf) + "' is outside of range.", VESPA_STRLOC);
} else if (errno == EINVAL) {
throw IllegalArgumentException("Illegal " + string(t) + " value '" + string(buf) + "'.", VESPA_STRLOC);
} else {
@@ -172,7 +173,16 @@ int getValue(double & val, const char *buf)
char *ebuf;
errno = 0;
val = locale::c::strtod(buf, &ebuf);
- if ((errno != 0) || (buf == ebuf)) {
+ bool failed = (buf == ebuf);
+ if (errno != 0) {
+ if (errno == ERANGE) {
+ if (val == HUGE_VAL) failed = true;
+ if (val == -HUGE_VAL) failed = true;
+ } else {
+ failed = true;
+ }
+ }
+ if (failed) {
throwInputError(errno, "double", buf);
}
return ebuf - buf;
@@ -183,7 +193,16 @@ int getValue(float & val, const char *buf)
char *ebuf;
errno = 0;
val = locale::c::strtof(buf, &ebuf);
- if ((errno != 0) || (buf == ebuf)) {
+ bool failed = (buf == ebuf);
+ if (errno != 0) {
+ if (errno == ERANGE) {
+ if (val == HUGE_VALF) failed = true;
+ if (val == -HUGE_VALF) failed = true;
+ } else {
+ failed = true;
+ }
+ }
+ if (failed) {
throwInputError(errno, "float", buf);
}
return ebuf - buf;