summaryrefslogtreecommitdiffstats
path: root/vespalib/src
diff options
context:
space:
mode:
authorHenning Baldersheim <balder@yahoo-inc.com>2019-06-20 14:14:59 +0200
committerGitHub <noreply@github.com>2019-06-20 14:14:59 +0200
commit801be7ad30e5e59879d4451efcb069954502ef16 (patch)
tree2244cdad6c77b9fc3b9f3fc2077879abe724d9f1 /vespalib/src
parentd5f07fd73977a9f9c5dbc396da15d0af18d49f22 (diff)
parentd9ff0d760dc19fa56c6a8cf59d6b5d5aac01d711 (diff)
Merge pull request #9814 from vespa-engine/balder/use-from_chars-in-stream
Use std::from_chars in stream.
Diffstat (limited to 'vespalib/src')
-rw-r--r--vespalib/src/tests/stllike/asciistream_test.cpp35
-rw-r--r--vespalib/src/vespa/vespalib/stllike/asciistream.cpp106
2 files changed, 66 insertions, 75 deletions
diff --git a/vespalib/src/tests/stllike/asciistream_test.cpp b/vespalib/src/tests/stllike/asciistream_test.cpp
index b1ba70e6ae2..fd362d9c49a 100644
--- a/vespalib/src/tests/stllike/asciistream_test.cpp
+++ b/vespalib/src/tests/stllike/asciistream_test.cpp
@@ -40,10 +40,21 @@ AsciistreamTest::verifyBothWays(T value, const char * expected)
os << value;
EXPECT_EQUAL(os.str(), string(expected));
EXPECT_EQUAL(os.size(), strlen(expected));
- T v;
- os >> v;
- EXPECT_EQUAL(value, v);
- EXPECT_TRUE(os.empty());
+ {
+ T v;
+ os >> v;
+ EXPECT_EQUAL(value, v);
+ EXPECT_TRUE(os.empty());
+ }
+
+ {
+ os << " " << expected;
+ T v;
+ os >> v;
+ EXPECT_EQUAL(value, v);
+ EXPECT_TRUE(os.empty());
+ EXPECT_EQUAL(0u, os.size());
+ }
}
template <typename T>
@@ -72,16 +83,16 @@ AsciistreamTest::testIllegalNumbers()
{
asciistream is("777777777777");
uint16_t s(0);
- EXPECT_EXCEPTION(is >> s, IllegalArgumentException, "An unsigned short can not represent '777777777777'");
+ EXPECT_EXCEPTION(is >> s, IllegalArgumentException, "strToInt value '777777777777' is outside of range");
EXPECT_EQUAL(12u, is.size());
uint32_t i(0);
- EXPECT_EXCEPTION(is >> i, IllegalArgumentException, "An unsigned int can not represent '777777777777'");
+ EXPECT_EXCEPTION(is >> i, IllegalArgumentException, "strToInt value '777777777777' is outside of range");
EXPECT_EQUAL(12u, is.size());
int16_t si(0);
- EXPECT_EXCEPTION(is >> si, IllegalArgumentException, "A short can not represent '777777777777'");
+ EXPECT_EXCEPTION(is >> si, IllegalArgumentException, "strToInt value '777777777777' is outside of range");
EXPECT_EQUAL(12u, is.size());
int32_t ii(0);
- EXPECT_EXCEPTION(is >> ii, IllegalArgumentException, "An int can not represent '777777777777'");
+ EXPECT_EXCEPTION(is >> ii, IllegalArgumentException, "strToInt value '777777777777' is outside of range");
EXPECT_EQUAL(12u, is.size());
is << "777777777777";
EXPECT_EQUAL(24u, is.size());
@@ -95,10 +106,10 @@ AsciistreamTest::testIllegalNumbers()
{
asciistream is("-77");
uint16_t s(0);
- EXPECT_EXCEPTION(is >> s, IllegalArgumentException, "An unsigned short can not represent '-77'");
+ EXPECT_EXCEPTION(is >> s, IllegalArgumentException, "Illegal strToInt value '-77'");
EXPECT_EQUAL(3u, is.size());
uint32_t i(0);
- EXPECT_EXCEPTION(is >> i, IllegalArgumentException, "An unsigned int can not represent '-77'");
+ EXPECT_EXCEPTION(is >> i, IllegalArgumentException, "Illegal strToInt value '-77'");
EXPECT_EQUAL(3u, is.size());
}
{
@@ -131,12 +142,12 @@ AsciistreamTest::testIllegalNumbers()
EXPECT_TRUE(is.empty());
{
uint32_t l(0);
- EXPECT_EXCEPTION(is >> l, IllegalArgumentException, "Failed decoding a unsigned long long from ''.");
+ EXPECT_EXCEPTION(is >> l, IllegalArgumentException, "buffer underflow at pos 0.");
EXPECT_TRUE(is.empty());
}
{
int32_t l(0);
- EXPECT_EXCEPTION(is >> l, IllegalArgumentException, "Failed decoding a long long from ''.");
+ EXPECT_EXCEPTION(is >> l, IllegalArgumentException, "buffer underflow at pos 0");
EXPECT_TRUE(is.empty());
}
{
diff --git a/vespalib/src/vespa/vespalib/stllike/asciistream.cpp b/vespalib/src/vespa/vespalib/stllike/asciistream.cpp
index 7d585cf1cf6..8114923a9fc 100644
--- a/vespalib/src/vespa/vespalib/stllike/asciistream.cpp
+++ b/vespalib/src/vespa/vespalib/stllike/asciistream.cpp
@@ -10,7 +10,8 @@
#include <limits>
#include <stdexcept>
#include <cassert>
-#include <math.h>
+#include <cmath>
+#include <charconv>
#include <vespa/log/log.h>
LOG_SETUP(".vespalib.stllike.asciistream");
@@ -77,9 +78,7 @@ asciistream::asciistream(stringref buf) :
}
}
-asciistream::~asciistream()
-{
-}
+asciistream::~asciistream() = default;
asciistream::asciistream(const asciistream & rhs) :
_rPos(0),
@@ -145,10 +144,11 @@ namespace {
int getValue(double & val, const char *buf) __attribute__((noinline));
int getValue(float & val, const char *buf) __attribute__((noinline));
-int getValue(unsigned long long & val, const char *buf) __attribute__((noinline));
-int getValue(long long & val, const char *buf) __attribute__((noinline));
void throwInputError(int e, const char * t, const char * buf) __attribute__((noinline));
+void throwInputError(std::errc e, const char * t, const char * buf) __attribute__((noinline));
void throwUnderflow(size_t pos) __attribute__((noinline));
+template <typename T>
+T strToInt(T & v, const char *begin, const char *end) __attribute__((noinline));
void throwInputError(int e, const char * t, const char * buf)
{
@@ -163,6 +163,16 @@ void throwInputError(int e, const char * t, const char * buf)
}
}
+void throwInputError(std::errc e, const char * t, const char * buf) {
+ if (e == std::errc::invalid_argument) {
+ throw IllegalArgumentException("Illegal " + string(t) + " value '" + string(buf) + "'.", VESPA_STRLOC);
+ } else if (e == std::errc::result_out_of_range) {
+ throw IllegalArgumentException(string(t) + " value '" + string(buf) + "' is outside of range.", VESPA_STRLOC);
+ } else {
+ throw IllegalArgumentException("Unknown error decoding an " + string(t) + " from '" + string(buf) + "'.", VESPA_STRLOC);
+ }
+}
+
void throwUnderflow(size_t pos)
{
throw IllegalArgumentException(make_string("buffer underflow at pos %ld.", pos), VESPA_STRLOC);
@@ -190,26 +200,28 @@ int getValue(float & val, const char *buf)
return ebuf - buf;
}
-int getValue(unsigned long long & val, const char *buf)
+template <typename T>
+T strToInt(T & v, const char *begin, const char *end)
{
- char *ebuf;
- errno = 0;
- val = strtoull(buf, &ebuf, 0);
- if ((errno != 0) || (buf == ebuf)) {
- throwInputError(errno, "unsigned long long", buf);
- }
- return ebuf - buf;
-}
+ const char * curr = begin;
+ for (;(curr < end) && std::isspace(*curr); curr++);
-int getValue(long long & val, const char *buf)
-{
- char *ebuf;
- errno = 0;
- val = strtoll(buf, &ebuf, 0);
- if ((errno != 0) || (buf == ebuf)) {
- throwInputError(errno, "long long", buf);
+ std::from_chars_result err;
+ if (((end - curr) > 2) && (curr[0] == '0') && ((curr[1] | 0x20) == 'x')) {
+ err = std::from_chars(curr+2, end, v, 16);
+ } else {
+ err = std::from_chars(curr, end, v, 10);
}
- return ebuf - buf;
+ if (err.ec == std::errc::invalid_argument) {
+ if (err.ptr >= end) {
+ throwUnderflow(err.ptr - begin);
+ }
+ throwInputError(err.ec, "strToInt", begin);
+ } else if (err.ec == std::errc::result_out_of_range) {
+ throwInputError(err.ec, "strToInt", begin);
+ }
+
+ return err.ptr - begin;
}
}
@@ -260,81 +272,49 @@ asciistream & asciistream::operator >> (unsigned char & v)
asciistream & asciistream::operator >> (unsigned short & v)
{
- unsigned long long l(0);
- size_t r = getValue(l, &_rbuf[_rPos]);
- if (l > std::numeric_limits<unsigned short>::max()) {
- throw IllegalArgumentException(make_string("An unsigned short can not represent '%lld'.", l), VESPA_STRLOC);
- }
- _rPos += r;
- v = l;
+ _rPos += strToInt(v, &_rbuf[_rPos], &_rbuf[length()]);
return *this;
}
asciistream & asciistream::operator >> (unsigned int & v)
{
- unsigned long long l(0);
- size_t r = getValue(l, &_rbuf[_rPos]);
- if (l > std::numeric_limits<unsigned int>::max()) {
- throw IllegalArgumentException(make_string("An unsigned int can not represent '%lld'.", l), VESPA_STRLOC);
- }
- _rPos += r;
- v = l;
+ _rPos += strToInt(v, &_rbuf[_rPos], &_rbuf[length()]);
return *this;
}
asciistream & asciistream::operator >> (unsigned long & v)
{
- unsigned long long l(0);
- _rPos += getValue(l, &_rbuf[_rPos]);
- v = l;
+ _rPos += strToInt(v, &_rbuf[_rPos], &_rbuf[length()]);
return *this;
}
asciistream & asciistream::operator >> (unsigned long long & v)
{
- unsigned long long l(0);
- _rPos += getValue(l, &_rbuf[_rPos]);
- v = l;
+ _rPos += strToInt(v, &_rbuf[_rPos], &_rbuf[length()]);
return *this;
}
asciistream & asciistream::operator >> (short & v)
{
- long long l(0);
- size_t r = getValue(l, &_rbuf[_rPos]);
- if ((l < std::numeric_limits<short>::min()) || (l > std::numeric_limits<short>::max())) {
- throw IllegalArgumentException(make_string("A short can not represent '%lld'.", l), VESPA_STRLOC);
- }
- _rPos += r;
- v = l;
+ _rPos += strToInt(v, &_rbuf[_rPos], &_rbuf[length()]);
return *this;
}
asciistream & asciistream::operator >> (int & v)
{
- long long l(0);
- size_t r = getValue(l, &_rbuf[_rPos]);
- if ((l < std::numeric_limits<int>::min()) || (l > std::numeric_limits<int>::max())) {
- throw IllegalArgumentException(make_string("An int can not represent '%lld'.", l), VESPA_STRLOC);
- }
- _rPos += r;
- v = l;
+ _rPos += strToInt(v, &_rbuf[_rPos], &_rbuf[length()]);
return *this;
}
asciistream & asciistream::operator >> (long & v)
{
- long long l(0);
- _rPos += getValue(l, &_rbuf[_rPos]);
- v = l;
+ _rPos += strToInt(v, &_rbuf[_rPos], &_rbuf[length()]);
return *this;
}
asciistream & asciistream::operator >> (long long & v)
{
- long long l(0);
- _rPos += getValue(l, &_rbuf[_rPos]);
- v = l;
+ _rPos += strToInt(v, &_rbuf[_rPos], &_rbuf[length()]);
return *this;
}