diff options
author | Henning Baldersheim <balder@oath.com> | 2019-06-14 21:39:34 +0000 |
---|---|---|
committer | Henning Baldersheim <balder@oath.com> | 2019-06-14 21:39:34 +0000 |
commit | 76f910b9387e486418957ee7aa4a2ea5ea1a762d (patch) | |
tree | 87590a002e1bcd8fe9aaed9798e1e6e774f525cf | |
parent | d8c31e9bb2254244d521dfba6fbefd18e2fa7c46 (diff) |
Use std::from_chars in stream.
-rw-r--r-- | vespalib/src/tests/stllike/asciistream_test.cpp | 16 | ||||
-rw-r--r-- | vespalib/src/vespa/vespalib/stllike/asciistream.cpp | 106 |
2 files changed, 51 insertions, 71 deletions
diff --git a/vespalib/src/tests/stllike/asciistream_test.cpp b/vespalib/src/tests/stllike/asciistream_test.cpp index b1ba70e6ae2..6e628d7e52c 100644 --- a/vespalib/src/tests/stllike/asciistream_test.cpp +++ b/vespalib/src/tests/stllike/asciistream_test.cpp @@ -72,16 +72,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 +95,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 +131,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..739eb2f6d78 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 - curr; } } @@ -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; } |